Compare commits
572 Commits
legacy
...
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 | ||
|
|
195d3a219a | ||
|
|
c6452c4f2b | ||
|
|
3dbacf0d65 | ||
|
|
56a82baf40 | ||
|
|
20d210245b | ||
|
|
21cbcf677a | ||
|
|
8fb355d03b | ||
|
|
218477404f | ||
|
|
766c0bc1b4 | ||
|
|
4a8d0666c2 | ||
|
|
8fac10a743 | ||
|
|
1aa4e8c5fb | ||
|
|
ee4c6ce699 | ||
|
|
b171f01d01 | ||
|
|
846070ebb5 | ||
|
|
9c766c2695 | ||
|
|
4752f5860a | ||
|
|
c2328e461e | ||
|
|
aa29bcf9fe | ||
|
|
f0b257aa12 | ||
|
|
93733e3721 | ||
|
|
501f506677 | ||
|
|
009de62828 | ||
|
|
b74c698866 | ||
| cd05e5e7fc | |||
|
|
f425510e11 | ||
|
|
1f635d2515 | ||
|
|
a61bddf0e8 | ||
|
|
843cb5b443 | ||
|
|
52347fd56d | ||
|
|
a20332e53d | ||
|
|
0aa469af81 | ||
|
|
0d73b13b28 | ||
|
|
24256798ba | ||
|
|
e61ab565c3 | ||
|
|
9cbcfa4720 | ||
|
|
c712fc741e | ||
|
|
ca5e4c13d3 | ||
|
|
37bd7e79d9 | ||
|
|
918f4e419c | ||
| 3abb11734a | |||
|
|
a5e921fd75 | ||
|
|
7dd93690d6 | ||
| 7dbffc6eef | |||
|
|
8b922082a7 | ||
|
|
19e3838df2 | ||
| 25e3ba1ed4 | |||
|
|
598bafe67f | ||
|
|
ebcc0aa76a | ||
|
|
e987fbbe8e | ||
| c41467c617 | |||
|
|
9ad32390d1 | ||
|
|
0d51cae4c8 | ||
|
|
91fa78e2d0 | ||
|
|
b13e217a5b | ||
|
|
b732a80eaa | ||
|
|
46c76b1703 | ||
|
|
db04bbb52e | ||
|
|
e425daf041 | ||
|
|
93548627a6 | ||
|
|
638ee88c96 | ||
|
|
50e88fa015 | ||
|
|
b3ae91d8f3 | ||
|
|
0077ae70d2 | ||
|
|
94744e01b9 | ||
|
|
8de88d6ad7 | ||
|
|
2d0804f90e | ||
|
|
d3577358d0 | ||
|
|
7346720894 | ||
|
|
b00bf6c180 | ||
|
|
eb306787ae | ||
|
|
643ea13207 | ||
|
|
6f1afc5b25 | ||
|
|
83d76f72da | ||
|
|
768ac776ed | ||
|
|
9995b93d2a | ||
|
|
4f609aeec7 | ||
|
|
b6eccaca6a | ||
|
|
cef99c2d72 | ||
|
|
86792eb56f | ||
|
|
a715bbd933 | ||
|
|
c2007ef090 | ||
|
|
b967240f8f | ||
|
|
839f9c6d6a | ||
|
|
f29e3ef97d | ||
|
|
79dd29cfc9 | ||
|
|
e082158592 | ||
|
|
e261641e59 | ||
|
|
5634fbed8a | ||
|
|
ceba38b1ac | ||
|
|
05f00b23d2 | ||
|
|
59f173c4e7 | ||
|
|
aeff5e09a2 | ||
|
|
4629626a31 | ||
|
|
4cf8c3f964 | ||
|
|
58eed49196 | ||
|
|
2983a0c0fd | ||
|
|
d22237d561 | ||
| e774f316e3 | |||
|
|
187a4c8555 | ||
|
|
65ff6bfbbf | ||
|
|
bd17e33537 | ||
| aede681d4b | |||
|
|
db1eac33a2 | ||
|
|
90861d7ee7 | ||
|
|
7a5c3a2e62 | ||
|
|
d73615e281 | ||
|
|
dcc1d81a74 | ||
|
|
b3632c0196 | ||
| 668c8d0075 | |||
| da6d86c785 | |||
|
|
575e92ead1 | ||
|
|
5f3d25fd75 | ||
|
|
952e14a5e7 | ||
|
|
895cd31d8e | ||
|
|
0da27e2c46 | ||
|
|
4936e9ca41 | ||
|
|
290b841517 | ||
|
|
99c982d6e1 | ||
|
|
15fc3699cf | ||
|
|
9ec05ef764 | ||
|
|
88eeb620ae | ||
|
|
6a363aeb5c | ||
|
|
c2cab407f3 | ||
|
|
08652c4ac1 | ||
|
|
1942508d8d | ||
| a4d2856bfc | |||
|
|
e8d2c2e142 | ||
|
|
4c8f03ca47 | ||
| 9971435716 | |||
|
|
b4dd91ad25 | ||
|
|
8bb6f901dc | ||
| 5ca24dab82 | |||
|
|
3ff06e043b | ||
|
|
e2cbfa3f48 | ||
|
|
857007c13c | ||
|
|
d16dfc1107 | ||
| abae7a5c22 | |||
|
|
149fda3b72 | ||
| 0ab83efd47 | |||
|
|
9eaff24cbb | ||
|
|
75ad4167b6 | ||
| f34dd95d77 | |||
| d424ccce49 | |||
| be87e41814 | |||
| 438c82bfb5 | |||
| f83e012d62 | |||
|
|
bc5d68ce18 | ||
|
|
863d980b2d | ||
|
|
f943e4801b | ||
|
|
78d749a8a9 | ||
| bc354f3798 | |||
| 8959e0d9f7 | |||
|
|
40ef92b230 | ||
|
|
4f0ae43411 | ||
|
|
229a8a29e8 | ||
|
|
2f9e9b1297 | ||
|
|
6812d685d0 | ||
|
|
a2303ee35f | ||
|
|
e3c2da36df | ||
|
|
0c7cd3e790 | ||
|
|
7a40008c1e | ||
|
|
07cadb8c62 | ||
|
|
d4611952d4 | ||
|
|
88c0061187 | ||
|
|
3684ee5e9b | ||
|
|
d1b921a5b0 | ||
|
|
bcb5a8c469 | ||
| 0534f607a5 | |||
| bae1da43d3 | |||
|
|
a3f5e0f27f | ||
|
|
227de53e84 | ||
|
|
d3f64ec79e | ||
|
|
8e79d6a6a8 | ||
|
|
60d1f48bd9 | ||
|
|
ee2b7c40b9 | ||
| 9b4d61c2b0 | |||
|
|
5b1e4513e2 | ||
|
|
0c42979423 | ||
|
|
36ac8607a9 | ||
|
|
4f4f34e281 | ||
|
|
8a5e12ec63 | ||
|
|
7d4c5d7be8 | ||
|
|
2dfb10e57b | ||
|
|
036cd628d3 | ||
|
|
9ee567530f | ||
|
|
e080e93faa | ||
|
|
efed1c0edb | ||
|
|
0c76052478 | ||
|
|
2af351efa8 | ||
|
|
949bbb0835 | ||
|
|
5ed81e4be9 | ||
| c5fc6219e1 | |||
| ba2bc60add | |||
|
|
8027c3d1bf | ||
|
|
dc77cc27da | ||
|
|
afa634f085 | ||
|
|
791a42bcd4 | ||
|
|
df1849180d | ||
| 27094846f7 | |||
|
|
ed4fbe5651 | ||
|
|
d04818ccd8 | ||
|
|
61c43962fb | ||
|
|
b4ad6870bf | ||
|
|
ea297d09bb | ||
|
|
85769e9d2c | ||
|
|
5714ed16d7 | ||
|
|
e919e96c53 | ||
|
|
442be8cbee | ||
|
|
df7a7c65d6 | ||
|
|
a409090b90 | ||
|
|
5cce1c79fc | ||
|
|
61c1e88dcf | ||
|
|
038ebaa268 | ||
|
|
91f62e1943 | ||
|
|
7986549fdd | ||
|
|
1d8da6579e | ||
|
|
0dff12232c | ||
|
|
a5e9e3c214 | ||
|
|
8e181b3010 | ||
|
|
44af9e16e4 | ||
|
|
7760e3acf4 | ||
|
|
a8ea3bc683 | ||
|
|
4c61ebd3fc | ||
|
|
591687eee8 | ||
|
|
261d2f2e84 | ||
|
|
3839bff29e | ||
|
|
78a6939929 | ||
|
|
3406e9a0e2 | ||
|
|
c51e6881d1 | ||
|
|
d70011016a | ||
|
|
f67280127a | ||
|
|
f932168f66 | ||
|
|
dc100b5d3a | ||
|
|
10eb9e4456 | ||
|
|
2f537b4f3e | ||
|
|
11303daebc | ||
|
|
60ab140c55 | ||
|
|
51bbd6590b | ||
|
|
346b9ced97 | ||
|
|
2992e784b0 | ||
|
|
2593b371d5 | ||
|
|
8f360206fb | ||
|
|
0c44849e15 | ||
|
|
f93a98e46a | ||
|
|
e5443122b4 | ||
|
|
28f192472b | ||
|
|
745f9dd6fb | ||
|
|
471e55dcea | ||
|
|
adbe8ac163 | ||
|
|
e44223084a | ||
|
|
7718d76be9 | ||
|
|
f22a3cd7c0 | ||
|
|
5abb2a4d4f | ||
|
|
74e6379d93 | ||
|
|
7f2a5893d4 | ||
|
|
89d03f4244 | ||
|
|
0c5bec8002 | ||
|
|
265652c420 | ||
|
|
208103d708 | ||
|
|
6ba8b68654 | ||
|
|
eba5d9f508 | ||
|
|
d9ee23c5bb | ||
|
|
d62b8d1af1 | ||
|
|
62f0851406 | ||
|
|
7ab5b157b1 | ||
|
|
a99a55788a | ||
|
|
3a48859ddd | ||
|
|
ced29975b2 | ||
|
|
84e8320e8f | ||
|
|
5f1c0231e4 | ||
|
|
b17c3fae6d | ||
|
|
19fe070491 | ||
|
|
8c069b7ad3 | ||
|
|
87799d8f02 | ||
| 07ec5abc3e | |||
|
|
ee37897df4 | ||
|
|
8a6e9070e0 | ||
|
|
8ab60c9f01 | ||
|
|
5eb7be246c | ||
|
|
fe599dfe75 | ||
|
|
23632d3c09 | ||
|
|
2a0150600f | ||
| 4d387e8063 | |||
| 3b588c2039 | |||
|
|
e73c9fe417 | ||
|
|
35fab34445 | ||
|
|
35f3c72250 | ||
|
|
c4a738f281 | ||
|
|
e0212d5109 | ||
|
|
152bc45776 | ||
|
|
91d930ee92 | ||
|
|
c6a48dd3f6 | ||
|
|
39947b3694 | ||
|
|
8df9ea55a9 | ||
|
|
bec2649fc1 | ||
|
|
1599e48d75 | ||
|
|
bda02826b1 | ||
| 58c2b4634a | |||
|
|
a30fecf8ec | ||
|
|
b27b21bbfc | ||
| 12d09b54cb | |||
|
|
25b35846e9 | ||
|
|
0f43796cd8 | ||
|
|
0f730d6c50 | ||
|
|
92462cf0df | ||
|
|
c49b094068 | ||
|
|
b34aacb067 | ||
|
|
103d2e0323 | ||
|
|
ad83ba4cdc | ||
|
|
e95ac42d57 | ||
|
|
ad18fbd162 | ||
|
|
bc3054aa43 | ||
|
|
53e7c7feda | ||
|
|
f8691207e3 | ||
|
|
5ad72af566 | ||
|
|
d1a336e903 | ||
|
|
5be79730b3 | ||
|
|
9d0f210548 | ||
|
|
387b508e40 | ||
|
|
0ed8d9c82d | ||
|
|
23276e5c7c | ||
|
|
37b5101e44 | ||
|
|
f04ff2fe26 | ||
|
|
13c69ef862 | ||
|
|
27d945f57c | ||
|
|
aef8c3d987 | ||
|
|
115d794ef9 | ||
|
|
bc935cc80a | ||
|
|
e54f488b17 | ||
|
|
cc7138949c | ||
|
|
74be880f9d | ||
|
|
5dbee6f0c3 | ||
|
|
cbb190bf4b | ||
|
|
4375118cd9 | ||
|
|
9aa78a02a5 | ||
|
|
1269731b55 | ||
|
|
79d7832d09 | ||
|
|
64fa12b10c | ||
|
|
56306ab944 | ||
|
|
923c673988 | ||
|
|
7e2f5eaed7 | ||
| 4dc8957c45 | |||
| cbb89c0db5 | |||
| ecdaadb83e | |||
| b480fa28b2 | |||
| 8493b482c4 | |||
| 18406b0c94 | |||
| 8b9cb065c2 | |||
| 7ee732b31e | |||
| e49fc295ba | |||
| b691bf3231 | |||
| 0777b822b3 | |||
| fc5af56bb7 | |||
|
|
c9d46b60ec | ||
| fd91c3b12e | |||
| 1bb6191244 | |||
| 063349d96d | |||
| d377afbf8b | |||
| ded3d96aae | |||
|
|
56f6456ce8 | ||
| 95e0544b73 | |||
| 9d6821127e | |||
|
|
0ba61534cb | ||
|
|
6cdcf4930d | ||
| b535a6eb32 | |||
|
|
0036dc5c80 | ||
|
|
dcc8a6d249 | ||
| 203b3bb340 | |||
| 200f67a1eb | |||
|
|
9105bcba15 | ||
|
|
07f75914bf | ||
|
|
cb3cb5d5fc | ||
|
|
4165d484bf | ||
|
|
7f138dafd0 | ||
|
|
5a8f6a8f1f | ||
|
|
e7ce014c70 | ||
|
|
40ece9f425 | ||
|
|
bd73e27db4 | ||
|
|
0695c70dbf | ||
|
|
9e0f9df9de | ||
|
|
8e3aa7ef33 | ||
|
|
1fdbe6294e | ||
|
|
93b65ac2ed | ||
|
|
28d93b3c25 | ||
|
|
863521fb3b | ||
|
|
837fddf804 | ||
|
|
677aa624d7 | ||
|
|
d390af3c79 | ||
|
|
6af805ba3a | ||
|
|
cd34601379 | ||
|
|
b800c58502 | ||
|
|
34a6449529 | ||
|
|
0273a23913 | ||
|
|
e6b4049403 | ||
|
|
b602b0b895 | ||
|
|
4ca97abd06 | ||
|
|
da9e7aac41 | ||
|
|
3568b8eb5e | ||
|
|
fa05d9c492 | ||
|
|
7cf34f2956 | ||
|
|
23e881f14c | ||
|
|
7eb3113ada | ||
|
|
f3a8a7db56 | ||
|
|
12f680d7e9 | ||
|
|
21b643000d | ||
|
|
7dec3c0c2a | ||
|
|
93f3a307b4 | ||
|
|
babc925967 | ||
|
|
58d7df499c | ||
|
|
b0512e392b | ||
|
|
b7878d81c6 | ||
|
|
9accd17bd4 | ||
|
|
bfeb2398aa | ||
|
|
2321540e97 | ||
|
|
ccea0f4bd1 | ||
|
|
00e00197ef | ||
|
|
85c7f7817c | ||
|
|
bb3b313fd2 | ||
|
|
52e34cb830 | ||
|
|
8b8433deaf | ||
|
|
4faca8c43b | ||
|
|
4455b10cc7 | ||
|
|
2d67b1218f | ||
|
|
fa1d7374bc | ||
|
|
c122e744ef | ||
|
|
708a136a5c | ||
|
|
f045b400a5 | ||
| dd2f696f8d | |||
|
|
b2b6a06280 | ||
|
|
1b51d65c89 | ||
|
|
a41cb3ed87 | ||
|
|
6521a4b2a9 | ||
|
|
e015a79526 | ||
|
|
359e65496f | ||
|
|
bb727f70be | ||
| ab2cd688fa | |||
|
|
f5e8fb5782 | ||
|
|
945e09b49e | ||
| 72b7a9d7b1 | |||
|
|
9cc299ced6 | ||
|
|
0560a01a55 | ||
|
|
1629c85818 | ||
|
|
5e98f45210 | ||
|
|
56643f9753 | ||
|
|
52431747ee | ||
|
|
6061295e0a | ||
|
|
89423d24b4 | ||
|
|
4f170db07d | ||
|
|
aea9b16f98 | ||
|
|
9658697d96 | ||
|
|
864afd8dcb | ||
|
|
1fac71dbd1 | ||
|
|
e199a0b766 | ||
|
|
4ae2966e98 | ||
|
|
e2c9955b41 | ||
|
|
9f1dcc667d | ||
|
|
fcfda3a447 | ||
|
|
486b2e4dfc | ||
|
|
ad85c2b816 | ||
|
|
2ddfde2642 | ||
|
|
882b5b4e00 | ||
|
|
6afd372945 | ||
|
|
6d4a4307cf | ||
|
|
fe4f0e7ecd | ||
|
|
32b73da959 | ||
|
|
d06b0f9f7a | ||
|
|
f28ab5182c | ||
|
|
e60242198a | ||
|
|
5be0cbbbf1 | ||
|
|
2462d24214 | ||
|
|
7dd53f3a94 | ||
|
|
c1910bacb0 | ||
|
|
2562e65d66 | ||
|
|
fe8c2378d2 | ||
|
|
f3bf746c6e | ||
|
|
353c43c987 | ||
|
|
04a82fb6a6 | ||
|
|
f48f39e67b | ||
|
|
1fa67f451a | ||
|
|
ebeb7d692b | ||
|
|
950c4a573a | ||
|
|
9b76f8afa0 | ||
|
|
007ade81a0 | ||
|
|
8b5fabce0c | ||
|
|
7401138d87 | ||
|
|
ad8a06d831 | ||
|
|
6d69cd2548 | ||
|
|
295b466505 | ||
|
|
1f2374927d | ||
|
|
6147289b40 | ||
|
|
0956525e94 | ||
|
|
2b952d0591 | ||
|
|
15e9ff92a8 | ||
|
|
b7c3d22961 | ||
|
|
9dbe0d7ff7 | ||
|
|
d9739cdb56 | ||
|
|
bc464cd264 | ||
|
|
00b8cd74b6 | ||
|
|
070c8ea486 | ||
|
|
46282a0406 | ||
|
|
e99ba5864a | ||
|
|
c9684beb5b | ||
|
|
2d940493a3 | ||
|
|
94e74deb24 | ||
|
|
f47ad8272f | ||
|
|
39016c93aa | ||
|
|
e9c420a873 | ||
|
|
beb61176c1 | ||
|
|
4ed52a3c9f | ||
|
|
723caca417 | ||
|
|
57d704b759 | ||
|
|
e9acddfa16 | ||
|
|
f3ee5a0854 | ||
|
|
5203d3acf8 | ||
|
|
b0eba78697 | ||
|
|
bce2717088 | ||
|
|
21d7056aae |
242
.dockerignore
Normal file
@@ -0,0 +1,242 @@
|
||||
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,node,react,storybookjs
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos,node,react,storybookjs
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
*.icloud
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-te
|
||||
node_modulesst
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
### Node Patch ###
|
||||
# Serverless Webpack directories
|
||||
.webpack/
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
# SvelteKit build / generate output
|
||||
.svelte-kit
|
||||
|
||||
### react ###
|
||||
.DS_*
|
||||
**/*.backup.*
|
||||
**/*.back.*
|
||||
|
||||
*.sublime*
|
||||
|
||||
psd
|
||||
thumb
|
||||
sketch
|
||||
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,node,react,storybookjs
|
||||
|
||||
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
||||
package-lock.json
|
||||
storybook-static/
|
||||
package/
|
||||
|
||||
# Version control
|
||||
.git
|
||||
.gitignore
|
||||
.gitattributes
|
||||
|
||||
# Dependencies
|
||||
.pnpm-store
|
||||
!pnpm-lock.yaml
|
||||
|
||||
# Testing
|
||||
coverage
|
||||
.nyc_output
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Docker
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
docker-compose*
|
||||
|
||||
# Documentation
|
||||
README.md
|
||||
CHANGELOG.md
|
||||
DOCKER_DEV_SETUP.md
|
||||
docs/
|
||||
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
|
||||
[*.nix]
|
||||
indent_size = 2
|
||||
3
.env.example
Normal file
@@ -0,0 +1,3 @@
|
||||
SENTRY_ORG=longhorn-developers
|
||||
SENTRY_PROJECT=ut-registration-plus
|
||||
SENTRY_AUTH_TOKEN=
|
||||
96
.eslintignore
Normal file
@@ -0,0 +1,96 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories and management
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
package.json
|
||||
package-lock.json
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# Webpack-built output
|
||||
/dist
|
||||
|
||||
# Extension archives
|
||||
/build
|
||||
|
||||
# VsCode
|
||||
.vscode/*
|
||||
!.vscode/launch.json
|
||||
!.vscode/tasks.json
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Terraform
|
||||
.terraform
|
||||
|
||||
# development dependencies
|
||||
.dev/vue-devtools
|
||||
.dev/browser-profiles
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
|
||||
# Sylelint IntelliJ Plugin Requirement
|
||||
.stylelintrc.json
|
||||
|
||||
# Local environment settings
|
||||
.env.local
|
||||
|
||||
*.svg
|
||||
|
||||
config
|
||||
.eslintrc.js
|
||||
!.storybook
|
||||
232
.eslintrc.cjs
Normal file
@@ -0,0 +1,232 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
node: true,
|
||||
webextensions: true,
|
||||
},
|
||||
ignorePatterns: ['*.html', 'tsconfig.json'],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
'plugin:storybook/recommended',
|
||||
'airbnb-base',
|
||||
'airbnb/rules/react',
|
||||
'airbnb-typescript',
|
||||
'@unocss',
|
||||
'prettier',
|
||||
],
|
||||
plugins: [
|
||||
'import',
|
||||
'import-essentials',
|
||||
'jsdoc',
|
||||
'eslint-plugin-tsdoc',
|
||||
'react-prefer-function-component',
|
||||
'@typescript-eslint',
|
||||
'simple-import-sort',
|
||||
],
|
||||
globals: {
|
||||
Atomics: 'readonly',
|
||||
SharedArrayBuffer: 'readonly',
|
||||
debugger: true,
|
||||
browser: true,
|
||||
context: true,
|
||||
JSX: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
ecmaVersion: 2022,
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
modules: true,
|
||||
experimentalObjectRestSpread: true,
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
jsdoc: {
|
||||
mode: 'typescript',
|
||||
},
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
alwaysTryTypes: true,
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'prefer-const': [
|
||||
'off',
|
||||
{
|
||||
destructuring: 'any',
|
||||
ignoreReadBeforeAssign: false,
|
||||
},
|
||||
],
|
||||
'no-plusplus': 'off',
|
||||
'no-inner-declarations': 'off',
|
||||
'sort-imports': 'off',
|
||||
'no-case-declarations': 'off',
|
||||
'no-unreachable': 'warn',
|
||||
'no-constant-condition': 'error',
|
||||
'space-before-function-paren': 'off',
|
||||
'no-undef': 'off',
|
||||
'no-return-await': 'off',
|
||||
'@typescript-eslint/return-await': 'off',
|
||||
'@typescript-eslint/no-shadow': ['off'],
|
||||
'@typescript-eslint/no-use-before-define': ['off'],
|
||||
'class-methods-use-this': 'off',
|
||||
'react-hooks/exhaustive-deps': 'warn',
|
||||
'@typescript-eslint/lines-between-class-members': 'off',
|
||||
'no-param-reassign': [
|
||||
'error',
|
||||
{
|
||||
props: false,
|
||||
},
|
||||
],
|
||||
'no-console': 'off',
|
||||
'consistent-return': 'off',
|
||||
'react/destructuring-assignment': 'off',
|
||||
'import/prefer-default-export': 'off',
|
||||
'no-promise-executor-return': 'off',
|
||||
'import/no-cycle': 'off',
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
'react/jsx-props-no-spreading': 'off',
|
||||
'react/jsx-no-useless-fragment': [
|
||||
'error',
|
||||
{
|
||||
allowExpressions: true,
|
||||
},
|
||||
],
|
||||
'keyword-spacing': [
|
||||
'error',
|
||||
{
|
||||
before: true,
|
||||
after: true,
|
||||
},
|
||||
],
|
||||
'no-continue': 'off',
|
||||
'space-before-blocks': [
|
||||
'error',
|
||||
{
|
||||
functions: 'always',
|
||||
keywords: 'always',
|
||||
classes: 'always',
|
||||
},
|
||||
],
|
||||
'react/jsx-filename-extension': [
|
||||
1,
|
||||
{
|
||||
extensions: ['.tsx'],
|
||||
},
|
||||
],
|
||||
'react/no-deprecated': 'warn',
|
||||
'react/prop-types': 'off',
|
||||
'react-prefer-function-component/react-prefer-function-component': [
|
||||
'warn',
|
||||
{
|
||||
allowComponentDidCatch: false,
|
||||
},
|
||||
],
|
||||
'react/function-component-definition': 'off',
|
||||
'react/button-has-type': 'off',
|
||||
'jsdoc/require-param-type': 'off',
|
||||
'jsdoc/require-returns-type': 'off',
|
||||
'jsdoc/newline-after-description': 'off',
|
||||
'react/require-default-props': 'off',
|
||||
'jsdoc/require-jsdoc': [
|
||||
'error',
|
||||
{
|
||||
enableFixer: false,
|
||||
publicOnly: true,
|
||||
checkConstructors: false,
|
||||
require: {
|
||||
ArrowFunctionExpression: true,
|
||||
ClassDeclaration: true,
|
||||
ClassExpression: true,
|
||||
FunctionExpression: true,
|
||||
},
|
||||
contexts: [
|
||||
'MethodDefinition:not([key.name="componentDidMount"]):not([key.name="render"])',
|
||||
'ArrowFunctionExpression',
|
||||
'ClassDeclaration',
|
||||
'ClassExpression',
|
||||
'ClassProperty:not([key.name="state"]):not([key.name="componentDidMount"])',
|
||||
'FunctionDeclaration',
|
||||
'FunctionExpression',
|
||||
'TSDeclareFunction',
|
||||
'TSEnumDeclaration',
|
||||
'TSInterfaceDeclaration',
|
||||
'TSMethodSignature',
|
||||
'TSModuleDeclaration',
|
||||
'TSTypeAliasDeclaration',
|
||||
],
|
||||
},
|
||||
],
|
||||
'tsdoc/syntax': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'warn',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
'@typescript-eslint/space-before-function-paren': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/no-empty-interface': 'warn',
|
||||
'import/no-restricted-paths': [
|
||||
'error',
|
||||
{
|
||||
zones: [
|
||||
{
|
||||
target: './src/background',
|
||||
from: './src/views',
|
||||
message:
|
||||
'You cannot import into the `background` directory from the `views` directory (i.e. content script files) because it will break the build!',
|
||||
},
|
||||
{
|
||||
target: './src/views',
|
||||
from: './src/background',
|
||||
message:
|
||||
'You cannot import into the `views` directory from the `background` directory (i.e. background script files) because it will break the build!',
|
||||
},
|
||||
{
|
||||
target: './src/shared',
|
||||
from: './',
|
||||
except: ['./src/shared', './node_modules'],
|
||||
message: 'You cannot import into `shared` from an external directory.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
'import/extensions': 'off',
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
'ForInStatement',
|
||||
'LabeledStatement',
|
||||
'WithStatement',
|
||||
{
|
||||
selector: 'TSEnumDeclaration',
|
||||
message: "Don't declare enums",
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/consistent-type-exports': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'simple-import-sort/imports': 'error',
|
||||
'simple-import-sort/exports': 'error',
|
||||
'import-essentials/restrict-import-depth': 'error',
|
||||
'import-essentials/check-path-alias': 'error',
|
||||
},
|
||||
};
|
||||
59
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG] "
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Pre-submission Checklist**
|
||||
|
||||
<!-- Please check all applicable boxes before submitting your issue -->
|
||||
|
||||
- [ ] I have searched existing issues to make sure this is not a duplicate
|
||||
- [ ] I have cleared my browser cache and confirmed the issue persists
|
||||
- [ ] I have checked this issue affects the latest version of the extension
|
||||
- [ ] I have disabled other extensions to ensure this isn't a conflict issue
|
||||
- [ ] I have included all the information requested below
|
||||
|
||||
**Bug Description**
|
||||
|
||||
<!-- A clear and concise description of what the bug is -->
|
||||
|
||||
**Steps To Reproduce**
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected Behavior**
|
||||
|
||||
<!-- A clear and concise description of what you expected to happen -->
|
||||
|
||||
**Current Behavior**
|
||||
|
||||
<!-- A clear and concise description of what actually happened -->
|
||||
|
||||
**Screenshots**
|
||||
|
||||
<!-- If applicable, add screenshots to help explain your problem -->
|
||||
|
||||
**Debug Information**
|
||||
|
||||
- UTRP Extension Version: [e.g. 1.2.0]
|
||||
- Browser Info: [e.g. Chrome 120.0.0]
|
||||
- OS: [e.g. Windows 11, macOS Sonoma]
|
||||
|
||||
**Console Logs**
|
||||
|
||||
<!-- Please check the browser console (F12) and paste any relevant error messages -->
|
||||
|
||||
```
|
||||
// Paste console logs here
|
||||
```
|
||||
|
||||
**Additional Context**
|
||||
|
||||
<!-- Add any other context about the problem here -->
|
||||
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea for this project
|
||||
title: "[FEATURE] "
|
||||
labels: feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Pre-submission Checklist**
|
||||
|
||||
<!-- Please check all applicable boxes before submitting your feature request -->
|
||||
|
||||
- [ ] I have searched existing issues to ensure this feature hasn't been requested
|
||||
- [ ] I have searched closed issues to check if this was previously rejected/implemented
|
||||
- [ ] I have checked the project roadmap (if available) for planned similar features
|
||||
- [ ] I have reviewed the documentation to confirm this feature doesn't exist
|
||||
- [ ] I have completed all sections below with detailed information
|
||||
|
||||
**Feature Description**
|
||||
|
||||
<!-- A clear and concise description of the feature you'd like to see -->
|
||||
|
||||
**Proposed Solution**
|
||||
|
||||
<!-- A clear and concise description of what you want to happen -->
|
||||
|
||||
**UI/UX Considerations**
|
||||
|
||||
<!-- If this feature involves UI changes, please describe the visual aspects -->
|
||||
|
||||
**Technical Implementation Details**
|
||||
|
||||
<!-- If you have specific technical suggestions, list them here -->
|
||||
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
@@ -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'
|
||||
43
.github/workflows/best-practices.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Best Practices
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run ESLint
|
||||
run: pnpm run lint
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run Prettier
|
||||
run: pnpm run prettier
|
||||
24
.github/workflows/check-types.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Type Check
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
type-check:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm run check-types
|
||||
26
.github/workflows/chromatic.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: 'Chromatic'
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
chromatic:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Publish to Chromatic
|
||||
uses: chromaui/action@latest
|
||||
with:
|
||||
projectToken: chpt_e8bd07b0b27d8eb
|
||||
exitZeroOnChanges: true
|
||||
autoAcceptChanges: 'main'
|
||||
25
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Create Release
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- production
|
||||
- preview
|
||||
jobs:
|
||||
build:
|
||||
name: build extension & create release
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Get file permission
|
||||
run: chmod -R 777 .
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Release with semantic-release
|
||||
id: semantic-release
|
||||
run: npx --no-install semantic-release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
24
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
43
.github/workflows/validate-pr.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Validate PR Title
|
||||
|
||||
# thank you ben limmer for this workflow:
|
||||
# https://github.com/blimmer/semantic-release-demo-2/blob/main/.github/workflows/lint-pr.yml
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v3.2.6
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Post Conventional Commit Comment (on failure)
|
||||
uses: jungwinter/comment@v1
|
||||
id: conventional-commit-help
|
||||
with:
|
||||
type: create
|
||||
issue_number: ${{ github.event.pull_request.number }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
Your pull request title did not conform to [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) standards. Our upcoming automated release pipeline will automatically determine
|
||||
the proper release version based on your pull request title.
|
||||
**Cheat Sheet**
|
||||
- feat: A new feature
|
||||
- fix: A bug fix
|
||||
- docs: Documentation only changes
|
||||
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
|
||||
- refactor: A code change that neither fixes a bug nor adds a feature
|
||||
- perf: A code change that improves performance
|
||||
- test: Adding missing tests or correcting existing tests
|
||||
- build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
|
||||
- ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
|
||||
- chore: Other changes that don't modify src or test files
|
||||
- revert: Reverts a previous commit
|
||||
if: ${{ failure() }}
|
||||
215
.gitignore
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,node,react,storybookjs
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos,node,react,storybookjs
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
*.icloud
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
### Node Patch ###
|
||||
# Serverless Webpack directories
|
||||
.webpack/
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
# SvelteKit build / generate output
|
||||
.svelte-kit
|
||||
|
||||
### react ###
|
||||
.DS_*
|
||||
**/*.backup.*
|
||||
**/*.back.*
|
||||
|
||||
node_modules
|
||||
|
||||
*.sublime*
|
||||
|
||||
psd
|
||||
thumb
|
||||
sketch
|
||||
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos,node,react,storybookjs
|
||||
|
||||
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
||||
package-lock.json
|
||||
storybook-static/
|
||||
package/
|
||||
|
||||
.direnv/
|
||||
1
.husky/commit-msg
Normal file
@@ -0,0 +1 @@
|
||||
npx --no -- commitlint --edit $1
|
||||
19
.prettierignore
Normal file
@@ -0,0 +1,19 @@
|
||||
*.css
|
||||
# macOS
|
||||
.DS_Store
|
||||
# Webpack-built output
|
||||
/dist
|
||||
|
||||
# Extension archives
|
||||
/build
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Dependency directories and management
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
package.json
|
||||
package-lock.json
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
12
.prettierrc.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"useTabs": false,
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "avoid",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"semi": true,
|
||||
"jsxSingleQuote": true
|
||||
}
|
||||
37
.releaserc.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"branches": [
|
||||
"production",
|
||||
{
|
||||
"name": "preview",
|
||||
"channel": "alpha",
|
||||
"prerelease": "alpha"
|
||||
}
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@semantic-release/commit-analyzer",
|
||||
{
|
||||
"preset": "conventionalcommits"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/release-notes-generator",
|
||||
{
|
||||
"preset": "conventionalcommits"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/exec",
|
||||
{
|
||||
"prepareCmd": "SEMANTIC_VERSION=${nextRelease.version} npm run build"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/github",
|
||||
{
|
||||
"assets": "build/**/artifacts/*.*",
|
||||
"failComment": false
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
24
.storybook/main.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { StorybookConfig } from '@storybook/react-vite';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-designs',
|
||||
'@storybook/test',
|
||||
'@chromatic-com/storybook',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
options: {
|
||||
builder: {
|
||||
viteConfigPath: '.storybook/vite-storybook.config.ts',
|
||||
},
|
||||
},
|
||||
},
|
||||
docs: {
|
||||
autodocs: 'tag',
|
||||
},
|
||||
};
|
||||
export default config;
|
||||
178
.storybook/preview.tsx
Normal file
@@ -0,0 +1,178 @@
|
||||
import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
|
||||
import type { Preview } from '@storybook/react';
|
||||
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
||||
import React from 'react';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
decorators: [
|
||||
Story => (
|
||||
<React.StrictMode>
|
||||
<ExtensionRoot>
|
||||
<Story />
|
||||
</ExtensionRoot>
|
||||
</React.StrictMode>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
let localData = {};
|
||||
type ListenerFunction = (
|
||||
changes: { [key: string]: chrome.storage.StorageChange },
|
||||
areaName: chrome.storage.AreaName
|
||||
) => void;
|
||||
const localDataListeners = new Map<
|
||||
ListenerFunction, // key to remove listener
|
||||
(changes: { [key: string]: chrome.storage.StorageChange }) => void
|
||||
>();
|
||||
|
||||
// mock chrome api
|
||||
globalThis.chrome = {
|
||||
storage: {
|
||||
local: {
|
||||
/**
|
||||
* Removes all items from storage.
|
||||
* @param callback Optional.
|
||||
* Callback on success, or on failure (in which case runtime.lastError will be set).
|
||||
*/
|
||||
async clear() {
|
||||
localData = {};
|
||||
},
|
||||
/**
|
||||
* Gets one or more items from storage.
|
||||
* @param keys A single key to get, list of keys to get, or a dictionary specifying default values.
|
||||
* An empty list or object will return an empty result object. Pass in null to get the entire contents of storage.
|
||||
* @return A Promise that resolves with an object containing items
|
||||
*/
|
||||
async get(keys?: string | string[] | { [key: string]: any } | null) {
|
||||
if (keys === null) {
|
||||
return localData;
|
||||
}
|
||||
if (Array.isArray(keys)) {
|
||||
return keys.reduce((acc, key) => {
|
||||
acc[key] = localData[key];
|
||||
return acc;
|
||||
}, {} as string); // funny types
|
||||
}
|
||||
if (typeof keys === 'string') {
|
||||
return { [keys]: localData[keys] };
|
||||
}
|
||||
return keys;
|
||||
},
|
||||
/**
|
||||
* Gets the amount of space (in bytes) being used by one or more items.
|
||||
* @param keys Optional. A single key or list of keys to get the total usage for. An empty list will return 0. Pass in null to get the total usage of all of storage.
|
||||
* @param callback Callback with the amount of space being used by storage, or on failure (in which case runtime.lastError will be set).
|
||||
* Parameter bytesInUse: Amount of space being used in storage, in bytes.
|
||||
*/
|
||||
async getBytesInUse() {
|
||||
return 0;
|
||||
},
|
||||
/**
|
||||
* Removes one or more items from storage.
|
||||
* @param keys A single key or a list of keys for items to remove.
|
||||
* @param callback Optional.
|
||||
* Callback on success, or on failure (in which case runtime.lastError will be set).
|
||||
*/
|
||||
async remove(keys: string | string[]) {
|
||||
if (Array.isArray(keys)) {
|
||||
keys.forEach(key => {
|
||||
for (const listener of localDataListeners.values()) {
|
||||
listener({ [key]: { oldValue: localData[key], newValue: undefined } });
|
||||
}
|
||||
|
||||
delete localData[key];
|
||||
});
|
||||
} else {
|
||||
for (const listener of localDataListeners.values()) {
|
||||
listener({ [keys]: { oldValue: localData[keys], newValue: undefined } });
|
||||
}
|
||||
|
||||
delete localData[keys];
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Sets multiple items.
|
||||
* @param items An object which gives each key/value pair to update storage with. Any other key/value pairs in storage will not be affected.
|
||||
* Primitive values such as numbers will serialize as expected. Values with a typeof "object" and "function" will typically serialize to {}, with the exception of Array (serializes as expected), Date, and Regex (serialize using their String representation).
|
||||
* @param callback Optional.
|
||||
* Callback on success, or on failure (in which case runtime.lastError will be set).
|
||||
*/
|
||||
async set(items: { [key: string]: any }) {
|
||||
for (const key in items) {
|
||||
const oldValue = localData[key];
|
||||
localData[key] = JSON.parse(JSON.stringify(items[key]));
|
||||
|
||||
for (const listener of localDataListeners.values()) {
|
||||
listener({ [key]: { oldValue: oldValue, newValue: localData[key] } });
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
onChanged: {
|
||||
/**
|
||||
* Registers an event listener callback to an event.
|
||||
* @param callback Called when an event occurs. The parameters of this function depend on the type of event.
|
||||
*/
|
||||
addListener(
|
||||
listener: (
|
||||
changes: { [key: string]: chrome.storage.StorageChange },
|
||||
areaName: chrome.storage.AreaName
|
||||
) => void
|
||||
) {
|
||||
localDataListeners.set(listener, (changes: { [key: string]: chrome.storage.StorageChange }) => {
|
||||
listener(changes, 'local');
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Deregisters an event listener callback from an event.
|
||||
* @param callback Listener that shall be unregistered.
|
||||
*/
|
||||
removeListener(listener: ListenerFunction) {
|
||||
localDataListeners.delete(listener);
|
||||
},
|
||||
},
|
||||
},
|
||||
runtime: {
|
||||
id: 'fake-id',
|
||||
getManifest(): chrome.runtime.Manifest {
|
||||
return {
|
||||
manifest_version: 3,
|
||||
name: 'fake-name',
|
||||
version: '0.0.0',
|
||||
};
|
||||
},
|
||||
onMessage: {
|
||||
/**
|
||||
* Registers an event listener callback to an event.
|
||||
* @param callback Called when an event occurs. The parameters of this function depend on the type of event.
|
||||
*/
|
||||
addListener<T extends Function>(callback: T) {},
|
||||
|
||||
/**
|
||||
* Deregisters an event listener callback from an event.
|
||||
* @param callback Listener that shall be unregistered.
|
||||
*/
|
||||
removeListener<T extends Function>(callback: T) {},
|
||||
},
|
||||
},
|
||||
} as typeof chrome;
|
||||
|
||||
// set updatedAt dates to be fixed
|
||||
|
||||
UserScheduleStore.get('schedules').then(schedules => {
|
||||
schedules.forEach(schedule => {
|
||||
schedule.updatedAt = new Date('2024-01-01 12:00').getTime();
|
||||
});
|
||||
UserScheduleStore.set('schedules', schedules);
|
||||
});
|
||||
|
||||
export default preview;
|
||||
28
.storybook/vite-storybook.config.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import react from '@vitejs/plugin-react-swc';
|
||||
import { resolve } from 'path';
|
||||
import UnoCSS from 'unocss/vite';
|
||||
import Icons from 'unplugin-icons/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
const root = resolve(__dirname, '../src');
|
||||
const pagesDir = resolve(root, 'pages');
|
||||
const assetsDir = resolve(root, 'assets');
|
||||
const publicDir = resolve(__dirname, '../public');
|
||||
|
||||
console.log(root);
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react(), UnoCSS(), Icons({ compiler: 'jsx', jsx: 'react' })],
|
||||
resolve: {
|
||||
alias: {
|
||||
src: root,
|
||||
'@assets': assetsDir,
|
||||
'@pages': pagesDir,
|
||||
'@public': publicDir,
|
||||
'@shared': resolve(root, 'shared'),
|
||||
'@background': resolve(pagesDir, 'background'),
|
||||
'@views': resolve(root, 'views'),
|
||||
},
|
||||
},
|
||||
});
|
||||
9
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"antfu.unocss",
|
||||
"editorconfig.editorconfig",
|
||||
"figma.figma-vscode-extension"
|
||||
]
|
||||
}
|
||||
18
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Run current script",
|
||||
"runtimeExecutable": "npx",
|
||||
"runtimeArgs": [
|
||||
"tsx"
|
||||
],
|
||||
"program": "${file}",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
40
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[yaml]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[svg]": {
|
||||
"editor.defaultFormatter": "jock.svg"
|
||||
},
|
||||
"material-icon-theme.activeIconPack": "react",
|
||||
"material-icon-theme.folders.associations": {
|
||||
"analytics": "Json",
|
||||
"background": "Delta",
|
||||
"navigation": "Routes",
|
||||
"logging": "log",
|
||||
"popup": "Layout",
|
||||
"storage": "Database",
|
||||
},
|
||||
"material-icon-theme.files.associations": {
|
||||
"tsconfig.extension.json": "tsconfig",
|
||||
"tsconfig.build.json": "tsconfig",
|
||||
"tsconfig.test.json": "tsconfig"
|
||||
},
|
||||
"[html]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
}
|
||||
11
@types/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_PACKAGE_VERSION: string;
|
||||
readonly VITE_SENTRY_ENVIRONMENT: string;
|
||||
readonly VITE_BETA_BUILD?: 'true';
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
390
CHANGELOG.md
Normal file
@@ -0,0 +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))
|
||||
|
||||
### 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))
|
||||
## [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))
|
||||
|
||||
### 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))
|
||||
## [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))
|
||||
|
||||
### 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))
|
||||
## [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))
|
||||
|
||||
### 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))
|
||||
## [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))
|
||||
|
||||
### 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))
|
||||
|
||||
### 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))
|
||||
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).
|
||||
89
DOCKER_DEV_SETUP.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Docker Dev Setup
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker installed on your machine
|
||||
- Git (to clone the repository)
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Clone the repository:
|
||||
|
||||
```
|
||||
git clone https://github.com/Longhorn-Developers/UT-Registration-Plus.git
|
||||
cd UT-Registration-Plus
|
||||
```
|
||||
|
||||
2. Build the Docker image:
|
||||
|
||||
```
|
||||
docker build -t ut-registration-plus .
|
||||
```
|
||||
|
||||
## Using Docker for Different Modes
|
||||
|
||||
The Docker setup supports three modes of operation: build, zip, and dev. You can choose the mode either by passing it as a command or by setting the `BUILD_MODE` environment variable.
|
||||
|
||||
### Build Mode (Default)
|
||||
|
||||
This mode builds the extension and places the output in the `dist` folder.
|
||||
|
||||
```
|
||||
docker run -it --rm -v $(pwd)/dist:/extension/dist ut-registration-plus build
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
docker run -it --rm -v $(pwd)/dist:/extension/dist -e BUILD_MODE=build ut-registration-plus
|
||||
```
|
||||
|
||||
### Zip Mode
|
||||
|
||||
This mode builds the extension and creates a zipped package in the `package` folder.
|
||||
|
||||
```
|
||||
docker run -it --rm -v $(pwd)/package:/extension/package ut-registration-plus zip
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
docker run -it --rm -v $(pwd)/package:/extension/package -e BUILD_MODE=zip ut-registration-plus
|
||||
```
|
||||
|
||||
### Development Mode with Hot Module Replacement (HMR)
|
||||
|
||||
This mode runs the extension in development mode with HMR support.
|
||||
|
||||
_Note_: This currently doesn't work.
|
||||
|
||||
```
|
||||
docker run -it --rm -v $(pwd)/dist:/extension/dist -v $(pwd)/dist:/extension/dist -p 5173:5173 ut-registration-plus dev
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
docker run -it --rm -v $(pwd)/dist:/extension/dist -p 5173:5173 -e BUILD_MODE=dev ut-registration-plus
|
||||
```
|
||||
|
||||
## Accessing the Built Extension
|
||||
|
||||
- For build mode, the extension files will be in the `dist` directory on your host machine.
|
||||
- For zip mode, the zipped extension will be in the `package` directory on your host machine.
|
||||
- For dev mode, the extension will be continuously built in the `dist` directory, and you can load it as an unpacked extension in Chrome.
|
||||
|
||||
## Docker Development Workflow
|
||||
|
||||
When working on the extension:
|
||||
|
||||
1. Run the container in dev mode
|
||||
2. Make changes to your source code
|
||||
3. The extension will automatically rebuild thanks to HMR
|
||||
4. Reload the extension in Chrome to see your changes
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If you encounter permission issues with the output directories, ensure that the directories exist on your host machine and have the correct permissions.
|
||||
- For any other issues, please check the Docker logs or open an issue in the GitHub repository.
|
||||
47
Dockerfile
Normal file
@@ -0,0 +1,47 @@
|
||||
# Stage 1: Base image with Node.js and pnpm
|
||||
FROM node:20.9.0-alpine AS base
|
||||
|
||||
# Install pnpm
|
||||
RUN npm install -g pnpm@latest-10
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package.json, pnpm-lock.yaml, and .nvmrc
|
||||
COPY package.json pnpm-lock.yaml .nvmrc ./
|
||||
|
||||
# Copy patches directory if it exists
|
||||
COPY patches ./patches
|
||||
|
||||
# Install dependencies, including applying patches
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Copy the rest of the source code
|
||||
COPY . .
|
||||
|
||||
# Stage 2: Final stage
|
||||
FROM base AS final
|
||||
|
||||
# Install zip utility and bash
|
||||
RUN apk add --no-cache zip bash
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /extension
|
||||
|
||||
# Copy all files from base
|
||||
COPY --from=base /app ./
|
||||
|
||||
# Copy the entrypoint script
|
||||
COPY docker-entrypoint.sh /usr/local/bin/
|
||||
|
||||
# Make the entrypoint script executable
|
||||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||
|
||||
# Expose port for HMR
|
||||
EXPOSE 5173
|
||||
|
||||
# Set the entrypoint to our new script
|
||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
||||
|
||||
# Set the default command (which can be overridden)
|
||||
CMD ["build"]
|
||||
21
LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Sriram Hariharan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
232
README.md
@@ -1,40 +1,218 @@
|
||||
|
||||
# UT Registration Plus
|
||||
## (or Sriram's Sexy Scheduling Script)
|
||||
[Try it for yourself on the Chrome Web Store](https://chrome.google.com/webstore/detail/hboadpjkoaieogjimneceaahlppnipaa)
|
||||
|
||||

|
||||
|
||||
We've all been there. 20 tabs of Rate My Professor, Catalyst, and the UT Course Catalog open and you still don't know what classes to take.
|
||||
This extension tries to streamline most of the unnecessary steps and headaches of registering for classes at UT Austin.
|
||||

|
||||

|
||||

|
||||
|
||||
**UT Registration Plus (UTRP)** streamlines the process of registering for classes at UT Austin by reducing the chaos of juggling multiple tabs like Rate My Professor, Google Sheets, and the UT Course Schedule. With UTRP, you can simplify class selection and schedule management. We've all been there. 20 tabs of Rate My Professor, Google Spreadsheet, and the UT Course Schedule open and you still don't know what classes to take.
|
||||
|
||||
- For each class on the UT Course Catalog it provides a "breakdown" popup, with quick and easy links to the RateMyProfessor and eCIS pages of the professor, as well as syllabi from when the professor taught the class in the past.
|
||||
## Demo
|
||||
|
||||
- Gets the course description and highlight the important information like prerequisites, restrictions, etc.
|
||||

|
||||
|
||||
- Shows an aggregate graph of the grade distributions for when the professor taught the class in the past.
|
||||
## Features
|
||||
|
||||
- Gives you the ability to "Save Courses" and view them in the extension popup. This lets you see any schedule conflicts, and makes copy-pasting the unique code much easier when you're actually registering.
|
||||
- **Quick Access to Class Info**: For each class in the UT Course Schedule, UTRP provides a "breakdown" popup with direct links to RateMyProfessor, Course Evaluation Surveys (CES), and past syllabi.
|
||||
- **Prerequisite & Restriction Highlights**: Displays course descriptions with highlighted details on prerequisites, restrictions, and other important info.
|
||||
- **Grade Distribution Graphs**: View an aggregate and semester-specific graph of grade distributions for each course.
|
||||
- **Saved Courses List**: Easily add courses to a list and view them in the extension popup. Copy unique numbers with a single click.
|
||||
- **Conflict Detection**: Automatically highlights and strikes out courses that conflict with your saved courses in the UT Course Catalog.
|
||||
- **Weekly Schedule View**: Displays your saved courses in a weekly schedule format for easier planning.
|
||||
- **Multiple Schedule Support**: Create multiple schedules to plan for different registration scenarios.
|
||||
- **And much more!**
|
||||
|
||||
- Highlights and crosses-out what courses on the UT Course Catalog would conflict with your currently saved courses, making selecting courses that fit with your schedule so much easier.
|
||||
## Toolchain
|
||||
|
||||
- Display's a weekly schedule based on your saved courses
|
||||
- React v20.9.0 (LTS)
|
||||
- TypeScript v5.x
|
||||
- Vite v5.x
|
||||
- pnpm v10.x
|
||||
- UnoCSS
|
||||
- ESLint
|
||||
- Prettier
|
||||
- Storybook
|
||||
- Figma
|
||||
- Semantic-Release
|
||||
- Custom Messaging & Storage Wrappers
|
||||
|
||||
<p align="center">
|
||||
<img src="https://lh3.googleusercontent.com/X5hqHGPU-F2lF3_shT2injxd40eFYXLJfZVxpU1v2w1YvFRW1jQMEXu2yzWHKKpqn5huJL-NEHY=w640-h400-e365">
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="https://lh3.googleusercontent.com/ZCRxTFKFjpGm5ZRMv2iHzMqdnrQHUx_Ih_XhGhy2O4Yn29YccvU5yXXrWXKuVKsNAmEJJ0As4xc=w640-h400-e365">
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="https://lh3.googleusercontent.com/3iRi25wDnVqgzc7pnYUXQq1TvdPpAeDjCmIF9hLU-WKmlchEYQUh_xU-XV00fEbKUr2XVKGkOw=w640-h400-e365">
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="https://lh3.googleusercontent.com/x95blI5D1mseNPLOtHETlLmoVtHm0eeye9uyeWSDd5W6m6fSoZxMMMyQTGUFo5swoTgRivGVyw=w640-h400-e365">
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="https://lh3.googleusercontent.com/bbey8OGOTtJWUaHGVIU5wewbWg6X6s-gjD15RwXHhvgH_9kax2mE4bcrjem_iZGH-q5z6NT7g94=w640-h400-e365">
|
||||
</p>
|
||||
## VSCode Extensions
|
||||
|
||||
# 2.0 coming soon....
|
||||
We recommend using the following VSCode extensions to improve your development experience:
|
||||
|
||||
- **[ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)**: For identifying and fixing linting issues.
|
||||
- **[Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)**: For automatic code formatting.
|
||||
- **[Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**: For Tailwind CSS class autocomplete and IntelliSense.
|
||||
- **[UnoCSS](https://marketplace.visualstudio.com/items?itemName=antfu.unocss)**: For better support with UnoCSS utilities.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome and encouraged! To get started:
|
||||
|
||||
1. **Fork** the repository.
|
||||
2. **Create a new branch**: `git checkout -b feature/your-feature`.
|
||||
3. **Make changes** and ensure your code passes linting and formatting checks: `pnpm run lint` and `pnpm run prettier`.
|
||||
4. **Commit your changes** following the [Conventional Commits](#conventional-commits--branch-naming-convention) specification.
|
||||
5. **Push** your branch: `git push origin feature/your-feature`.
|
||||
6. **Open a Pull Request**.
|
||||
|
||||
For significant changes, it’s recommended to open an issue first to discuss the proposed updates.
|
||||
|
||||
## Development
|
||||
|
||||
### Getting Started
|
||||
|
||||
1. Clone this repository: `git clone https://github.com/Longhorn-Developers/UT-Registration-Plus.git`
|
||||
2. **Node Version**: This project requires the Node.js version specified in `.nvmrc`. Use [nvm](https://github.com/nvm-sh/nvm) to install and manage the correct version:
|
||||
```bash
|
||||
nvm install
|
||||
nvm use
|
||||
```
|
||||
_Note: Installing the wrong Node version can lead to errors during setup._
|
||||
3. Install dependencies using `pnpm` (which manages and patches dependencies):
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
Once set up, the extension can be built to the `dist/` directory using the following methods:
|
||||
|
||||
### Development Builds
|
||||
|
||||
- Run the development server:
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
> **Note**: Injected content on UT pages may not display correctly in development mode. To develop with accurate styles, use the following command:
|
||||
>
|
||||
> ```bash
|
||||
> NODE_ENV='development' pnpm run dev build --mode development -w
|
||||
> ```
|
||||
|
||||
### Production Builds
|
||||
|
||||
- To generate production builds:
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Beta Builds</summary>
|
||||
|
||||
Use `BETA=true pnpm build` to generate a beta build.
|
||||
|
||||
</details>
|
||||
|
||||
### Docker
|
||||
|
||||
This project includes a Dockerfile that allows you to build, zip, or run the extension in development mode using Docker. Refer to [Docker Dev Setup](./DOCKER_DEV_SETUP.md) to get started.
|
||||
|
||||
## Loading the Extension Manually
|
||||
|
||||
To load the extension manually in Chrome:
|
||||
|
||||
1. Open `chrome://extensions`.
|
||||
2. Enable 'Developer Mode'.
|
||||
3. Click 'Load unpacked'.
|
||||
4. Navigate to the `dist/` directory and select it.
|
||||
|
||||
## Bug Reporting
|
||||
|
||||
If you encounter bugs or issues, please report them in the [Issues](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues) section, including:
|
||||
|
||||
- A clear, descriptive title
|
||||
- Steps to reproduce the issue
|
||||
- Expected behavior
|
||||
- Screenshots or logs (if applicable)
|
||||
|
||||
We aim to address issues promptly.
|
||||
|
||||
## Conventional Commits & Branch Naming Convention
|
||||
|
||||
We follow the **Conventional Commits** specification for commit messages. This ensures a consistent commit history and enables automated versioning and changelog generation.
|
||||
|
||||
### Commit Messages
|
||||
|
||||
Follow this structure for commit messages:
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- **type**: One of the following:
|
||||
- `feat`: A new feature
|
||||
- `fix`: A bug fix
|
||||
- `docs`: Documentation updates
|
||||
- `style`: Code formatting changes (whitespace, semicolons, etc.)
|
||||
- `refactor`: Code restructuring (without adding features or fixing bugs)
|
||||
- `test`: Adding or modifying tests
|
||||
- `chore`: Maintenance tasks or build process changes
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
feat(auth): add login functionality
|
||||
fix(ui): align buttons in navbar
|
||||
```
|
||||
|
||||
### Branch Naming
|
||||
|
||||
Branch names should follow the format:
|
||||
|
||||
```
|
||||
<type>/<short-description>
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
- `feat/user-login`
|
||||
- `fix/navbar-layout`
|
||||
- `docs/update-readme`
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See the [LICENSE](./LICENSE.md) for more details.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
We maintain a strict code of conduct. By contributing, you agree to adhere to the rules outlined in [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md).
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Special thanks to the developers and contributors behind these amazing tools and libraries:
|
||||
|
||||
- React v20.9.0 (LTS)
|
||||
- TypeScript v5.x
|
||||
- Vite v5.x
|
||||
- pnpm v10.x
|
||||
- UnoCSS
|
||||
- ESLint
|
||||
- Prettier
|
||||
- Storybook
|
||||
- Figma
|
||||
- Semantic-Release
|
||||
- [chrome-extension-toolkit](https://github.com/sghsri/chrome-extension-toolkit)
|
||||
- [UT_Grade_Parser](https://github.com/doprz/UT_Grade_Parser)
|
||||
- [eslint-plugin-import-essentials](https://github.com/doprz/eslint-plugin-import-essentials)
|
||||
- [UT Registration Plus v1.2.2.7](https://github.com/Longhorn-Developers/UT-Registration-Plus/tree/legacy) by @sghsri
|
||||
- [UT Registration Planner](https://github.com/doprz/UT-Registration-Planner) by @doprz
|
||||
- [Figma Designs](https://www.figma.com/design/8tsCay2FRqctrdcZ3r9Ahw/UTRP) by @IsaDavRod
|
||||
- [Longhorn Developers](https://github.com/Longhorn-Developers) - established in 2024
|
||||
- The UTRP devs, beta testers, and all supporters of the project!
|
||||
|
||||
## Activity
|
||||
|
||||

|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://star-history.com/#Longhorn-Developers/UT-Registration-Plus&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=Longhorn-Developers/UT-Registration-Plus&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=Longhorn-Developers/UT-Registration-Plus&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=Longhorn-Developers/UT-Registration-Plus&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- This file is the html file serving the "My Schedule / Calendar" page. -->
|
||||
<head>
|
||||
<link rel='stylesheet' href='css/fullcalendar.min.css' />
|
||||
<link rel='stylesheet' href='css/_materialFullCalendar.css' />
|
||||
<script src='js/lib/jquery-3.3.1.min.js'></script>
|
||||
<script src='js/lib/moment.min.js'></script>
|
||||
<script src='js/lib/fullcalendar.min.js'></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style='display:flex'>
|
||||
<div id='calendar' style="flex-grow: 1"></div>
|
||||
<div class="card" id="header"
|
||||
style="text-align:center;margin:5px 0px 0px 15px;display: inline-table;padding-bottom: 5px;">
|
||||
<h1 id='hours'
|
||||
style="font-size:30px;font-weight:500; border-bottom: 3px solid black;display: inline-block;padding-bottom: 5px;margin-bottom: 5px;">
|
||||
0
|
||||
hours</h1>
|
||||
<h1 id='num' style="font-size:20px;font-weight:500; margin: 2px;">0
|
||||
Courses</h1>
|
||||
<br>
|
||||
<div style="margin:5px;display: flex;flex-direction: column;">
|
||||
<button id="clear" class="matbut"
|
||||
style="font-size:medium; background:#4CAF50;margin: 10px;white-space: nowrap;text-align: center;">Clear
|
||||
All</button>
|
||||
<button id="save" class="matbut"
|
||||
style="font-size:medium; background:#FF9800;margin: 10px;white-space: nowrap;text-align: center;">Save
|
||||
as PNG</button>
|
||||
<button id="export" class="matbut"
|
||||
style="font-size:medium; background:#FF0000;margin: 10px;white-space: nowrap;text-align: center;">Export
|
||||
Cal</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src='js/config.js'></script>
|
||||
<script src='js/lib/html2canvas.min.js'></script>
|
||||
<script src='js/lib/ics.min.js'></script>
|
||||
<script src='js/Template.js'></script>
|
||||
<script src='js/util.js'></script>
|
||||
<script src='js/calendar.js'></script>
|
||||
5
chromatic.config.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"onlyChanged": true,
|
||||
"projectId": "Project:65c5172964f36dcf207985bf",
|
||||
"zip": true
|
||||
}
|
||||
122
commitlint.config.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { RuleConfigCondition, RuleConfigSeverity, TargetCaseType } from '@commitlint/types';
|
||||
|
||||
export default {
|
||||
parserPreset: 'conventional-changelog-conventionalcommits',
|
||||
rules: {
|
||||
'body-leading-blank': [RuleConfigSeverity.Warning, 'always'] as const,
|
||||
'footer-leading-blank': [RuleConfigSeverity.Warning, 'always'] as const,
|
||||
'footer-max-line-length': [RuleConfigSeverity.Error, 'always', 100] as const,
|
||||
'header-max-length': [RuleConfigSeverity.Error, 'always', 100] as const,
|
||||
'header-trim': [RuleConfigSeverity.Error, 'always'] as const,
|
||||
'subject-case': [
|
||||
RuleConfigSeverity.Error,
|
||||
'never',
|
||||
['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
|
||||
] as [RuleConfigSeverity, RuleConfigCondition, TargetCaseType[]],
|
||||
'subject-empty': [RuleConfigSeverity.Error, 'never'] as const,
|
||||
'subject-full-stop': [RuleConfigSeverity.Error, 'never', '.'] as const,
|
||||
'type-case': [RuleConfigSeverity.Error, 'always', 'lower-case'] as const,
|
||||
'type-empty': [RuleConfigSeverity.Error, 'never'] as const,
|
||||
'type-enum': [
|
||||
RuleConfigSeverity.Error,
|
||||
'always',
|
||||
['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test'],
|
||||
] as [RuleConfigSeverity, RuleConfigCondition, string[]],
|
||||
},
|
||||
prompt: {
|
||||
questions: {
|
||||
type: {
|
||||
description: "Select the type of change that you're committing",
|
||||
enum: {
|
||||
feat: {
|
||||
description: 'A new feature',
|
||||
title: 'Features',
|
||||
emoji: '✨',
|
||||
},
|
||||
fix: {
|
||||
description: 'A bug fix',
|
||||
title: 'Bug Fixes',
|
||||
emoji: '🐛',
|
||||
},
|
||||
docs: {
|
||||
description: 'Documentation only changes',
|
||||
title: 'Documentation',
|
||||
emoji: '📚',
|
||||
},
|
||||
style: {
|
||||
description:
|
||||
'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)',
|
||||
title: 'Styles',
|
||||
emoji: '💎',
|
||||
},
|
||||
refactor: {
|
||||
description: 'A code change that neither fixes a bug nor adds a feature',
|
||||
title: 'Code Refactoring',
|
||||
emoji: '📦',
|
||||
},
|
||||
perf: {
|
||||
description: 'A code change that improves performance',
|
||||
title: 'Performance Improvements',
|
||||
emoji: '🚀',
|
||||
},
|
||||
test: {
|
||||
description: 'Adding missing tests or correcting existing tests',
|
||||
title: 'Tests',
|
||||
emoji: '🚨',
|
||||
},
|
||||
build: {
|
||||
description:
|
||||
'Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)',
|
||||
title: 'Builds',
|
||||
emoji: '🛠',
|
||||
},
|
||||
ci: {
|
||||
description:
|
||||
'Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)',
|
||||
title: 'Continuous Integrations',
|
||||
emoji: '⚙️',
|
||||
},
|
||||
chore: {
|
||||
description: "Other changes that don't modify src or test files",
|
||||
title: 'Chores',
|
||||
emoji: '♻️',
|
||||
},
|
||||
revert: {
|
||||
description: 'Reverts a previous commit',
|
||||
title: 'Reverts',
|
||||
emoji: '🗑',
|
||||
},
|
||||
},
|
||||
},
|
||||
scope: {
|
||||
description: 'What is the scope of this change (e.g. component or file name)',
|
||||
},
|
||||
subject: {
|
||||
description: 'Write a short, imperative tense description of the change',
|
||||
},
|
||||
body: {
|
||||
description: 'Provide a longer description of the change',
|
||||
},
|
||||
isBreaking: {
|
||||
description: 'Are there any breaking changes?',
|
||||
},
|
||||
breakingBody: {
|
||||
description:
|
||||
'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself',
|
||||
},
|
||||
breaking: {
|
||||
description: 'Describe the breaking changes',
|
||||
},
|
||||
isIssueAffected: {
|
||||
description: 'Does this change affect any open issues?',
|
||||
},
|
||||
issuesBody: {
|
||||
description:
|
||||
'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself',
|
||||
},
|
||||
issues: {
|
||||
description: 'Add issue references (e.g. "fix #123", "re #123".)',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,344 +0,0 @@
|
||||
/*
|
||||
|
||||
This is the Material Design theme for FullCalendar Weekly Agenda view
|
||||
|
||||
Creation Date: Aug 19th 2015
|
||||
Author: Jacky Liang
|
||||
Version: FullCalendar 2.4.0
|
||||
Tested Using the Following FC Settings:
|
||||
|
||||
editable: false,
|
||||
handleWindowResize: true,
|
||||
weekends: false, // Hide weekends
|
||||
defaultView: 'agendaWeek', // Only show week view
|
||||
header: false, // Hide buttons/titles
|
||||
minTime: '07:30:00', // Start time for the calendar
|
||||
maxTime: '22:00:00', // End time for the calendar
|
||||
columnFormat: {
|
||||
week: 'ddd' // Only show day of the week names
|
||||
},
|
||||
displayEventTime: true,
|
||||
allDayText: 'Online/TBD'
|
||||
|
||||
Note: This has NOT been tested on Monthly or Daily views.
|
||||
|
||||
Colors: Use the following - https://www.google.com/design/spec/style/color.html#color-color-palette
|
||||
at the 700 level. An opacity of 0.65 is automatically applied to the
|
||||
700 level colors to generate a soft and pleasing look.
|
||||
|
||||
Color were applied to each event using the following code:
|
||||
|
||||
events.push({
|
||||
title: 'This is a Material Design event!',
|
||||
start: 'someStartDate',
|
||||
end: 'someEndDate',
|
||||
color: '#C2185B'
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
.fc-state-highlight {
|
||||
opacity: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Styling for each event from Schedule */
|
||||
|
||||
.fc-time-grid-event.fc-v-event.fc-event {
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.3);
|
||||
transition: 0.3s;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.html2canvas-container {
|
||||
width: 3000px !important;
|
||||
height: 3000px !important;
|
||||
}
|
||||
|
||||
|
||||
.fc-time-grid-event.fc-v-event.fc-event:hover {
|
||||
box-shadow: 0 8px 12px 0 rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Bolds the name of the event and inherits the font size */
|
||||
|
||||
.fc-event {
|
||||
font-size: small !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
/* Remove the header border from Schedule */
|
||||
|
||||
.fc td,
|
||||
.fc th {
|
||||
border-style: ridge !important;
|
||||
border-width: 1px !important;
|
||||
padding: 4px 3px 0px 3px !important;
|
||||
vertical-align: top !important;
|
||||
border-left-width: 0;
|
||||
|
||||
}
|
||||
|
||||
.fc-row fc-widget-header {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.fc td {
|
||||
border-top-width: 0;
|
||||
padding: 3px !important;
|
||||
}
|
||||
|
||||
.fc-widget-header {
|
||||
background-color: #cc5500;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Inherits background for each event from Schedule. */
|
||||
|
||||
.fc-event .fc-bg {
|
||||
z-index: 1 !important;
|
||||
background: inherit !important;
|
||||
opacity: 0.25 !important;
|
||||
}
|
||||
|
||||
/* Normal font weight for the time in each event */
|
||||
|
||||
.fc-time-grid-event .fc-time {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
||||
/* Apply same opacity to all day events */
|
||||
|
||||
.fc-ltr .fc-h-event.fc-not-end,
|
||||
.fc-rtl .fc-h-event.fc-not-start {
|
||||
opacity: 0.65 !important;
|
||||
margin-left: 12px !important;
|
||||
padding: 5px !important;
|
||||
}
|
||||
|
||||
/* Apply same opacity to all day events */
|
||||
|
||||
.fc-day-grid-event.fc-h-event.fc-event.fc-not-start.fc-end {
|
||||
opacity: 0.65 !important;
|
||||
margin-left: 12px !important;
|
||||
padding: 5px !important;
|
||||
}
|
||||
|
||||
/* Material design button */
|
||||
|
||||
.matbut {
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
margin: 10px 10px 10px 0px;
|
||||
padding: 10px 10px;
|
||||
border-radius: 10px;
|
||||
font-size: medium;
|
||||
font-style: bold;
|
||||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.matbut {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.matbut:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
opacity: 0;
|
||||
border-radius: 100%;
|
||||
transform: scale(1, 1) translate(-50%);
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
0% {
|
||||
transform: scale(0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
20% {
|
||||
transform: scale(25, 25);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(40, 40);
|
||||
}
|
||||
}
|
||||
|
||||
.matbut:focus:not(:active)::after {
|
||||
animation: ripple 1s ease-out;
|
||||
}
|
||||
|
||||
.fc-button {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
min-height: 36px;
|
||||
min-width: 88px;
|
||||
line-height: 36px;
|
||||
vertical-align: middle;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
outline: none;
|
||||
border: 0;
|
||||
padding: 0 6px;
|
||||
margin: 6px 8px;
|
||||
letter-spacing: 0.01em;
|
||||
background: transparent;
|
||||
color: currentColor;
|
||||
white-space: nowrap;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
font-style: inherit;
|
||||
font-variant: inherit;
|
||||
font-family: inherit;
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
-webkit-transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
|
||||
.fc-button:hover {
|
||||
background-color: rgba(158, 158, 158, 0.2);
|
||||
}
|
||||
|
||||
.fc-button:focus,
|
||||
.fc-button:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* The active button box is ugly so the active button will have the same appearance of the hover */
|
||||
|
||||
.fc-state-active {
|
||||
background-color: rgba(158, 158, 158, 0.2);
|
||||
}
|
||||
|
||||
/* Not raised button */
|
||||
|
||||
.fc-state-default {
|
||||
box-shadow: None;
|
||||
}
|
||||
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
padding-top: 300px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgb(0, 0, 0);
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
#classname {
|
||||
font-weight: bold;
|
||||
margin-bottom: -10px;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fefefe;
|
||||
margin: auto;
|
||||
max-height: 85%;
|
||||
overflow-y: auto;
|
||||
padding: 15px;
|
||||
border: 1px solid #888;
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
#prof {
|
||||
font-size: medium;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
#info {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
body a:link,
|
||||
body a:visited {
|
||||
font-weight: bold;
|
||||
color: #3c87a3;
|
||||
}
|
||||
|
||||
.time {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 5px;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.fc td,
|
||||
.fc th {
|
||||
border-color: #E7E7E7;
|
||||
|
||||
}
|
||||
|
||||
.fc-time-grid .fc-slats td {
|
||||
height: 1.5em;
|
||||
border-bottom: initial;
|
||||
border-color: #E7E7E7;
|
||||
}
|
||||
|
||||
/* The Close Button */
|
||||
|
||||
.close {
|
||||
color: #aaaaaa;
|
||||
float: right;
|
||||
padding: 5px;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card {
|
||||
transition: 0.3s;
|
||||
margin-bottom: 5px;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.2), 0 4px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
|
||||
|
||||
.cardcontainer {
|
||||
padding: 2px 16px;
|
||||
display: block;
|
||||
transition: width 300ms ease-in-out, height 300ms ease-in-out;
|
||||
}
|
||||
|
||||
|
||||
tbody {
|
||||
border-width: 0px;
|
||||
}
|
||||
5
css/fullcalendar.min.css
vendored
@@ -1,81 +0,0 @@
|
||||
.version {
|
||||
padding: 0px 5px 5px 0px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.creator-tag {
|
||||
margin: 10px 5px 5px 0px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.options-card {
|
||||
width: 400px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: auto;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
#version-container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.options-header {
|
||||
padding: 16px 16px 0px 16px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#contributors_container {
|
||||
text-align: center;
|
||||
margin-top: 30;
|
||||
padding: 5px 20px 20px 20px;
|
||||
width: auto;
|
||||
margin-right: 20%;
|
||||
margin-left: 20%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#contributor-list {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-gap: 1rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
}
|
||||
|
||||
.contributor-card {
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
display: grid;
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.contributor-card img {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.contributor-name {
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.contributor-username {
|
||||
margin: 0 0 5px 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.contributor-title {
|
||||
margin-bottom: 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.open-source-tag {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
563
css/popup.css
@@ -1,563 +0,0 @@
|
||||
.card {
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
||||
transition: 0.3s;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.2), 0 4px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 3px 16px 3px 12px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding: 10px 0px 0 10px;
|
||||
}
|
||||
|
||||
li {
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
body {
|
||||
min-width: 370px;
|
||||
min-height: 400px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.conflict_message{
|
||||
font-size:small;
|
||||
font-weight:bold;
|
||||
color:red;
|
||||
margin:5px 5px 5px 10px;
|
||||
}
|
||||
|
||||
.course_list {
|
||||
list-style-type: none;
|
||||
padding: 5px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.course_list_card {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.course_list_item {
|
||||
padding: 0px 5px 5px 5px;
|
||||
overflow-y: auto;
|
||||
max-height:400px;
|
||||
}
|
||||
|
||||
.course_list_item_subtext {
|
||||
font-size:medium;
|
||||
}
|
||||
|
||||
.empty_message {
|
||||
font-weight: normal;
|
||||
font-size: large;
|
||||
margin: 60px 30px 200px 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#empty #main {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#empty span {
|
||||
font-size: small;
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.time_line_days {
|
||||
display:inline-block;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.time_line_hours {
|
||||
margin-left:10px;
|
||||
display:inline-block;
|
||||
width: 50%;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.time_line_location {
|
||||
float:right;
|
||||
display:inline-block;
|
||||
text-align:right;
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.time_line_location_link {
|
||||
color:#3c87a3;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.more_info_button{
|
||||
background: #2196F3;
|
||||
}
|
||||
|
||||
.remove_button {
|
||||
background: #F44336;
|
||||
}
|
||||
|
||||
.register_button {
|
||||
background: #4CAF50;
|
||||
}
|
||||
|
||||
.settings_button {
|
||||
margin-right: 2px;
|
||||
border: 0px;
|
||||
border-radius: 50%;
|
||||
transition: 0.3s;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
|
||||
.settings_button:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.settings_button:hover {
|
||||
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.16), 0 4px 15px 0 rgba(0, 0, 0, 0.12);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.selected {
|
||||
box-shadow: 0 0 0 1pt #FF9800;
|
||||
}
|
||||
|
||||
.settings_button:focus:after:hover {
|
||||
outline: 0;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.copy_button {
|
||||
background-color: transparent;
|
||||
padding: 0px;
|
||||
border: none;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
transition: .2s;
|
||||
}
|
||||
|
||||
.copy_button:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.shadow {
|
||||
box-shadow: 0 2px 20px 0 rgba(0, 0, 0, 0.2), 0 4px 20px 0 rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
i {
|
||||
padding: 4px 0px;
|
||||
}
|
||||
|
||||
.copy_button_icon {
|
||||
color:white;
|
||||
float:left;
|
||||
border-radius: 50%;
|
||||
padding: 3px;
|
||||
text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.16);
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
.header_container{
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.header_buttons {
|
||||
padding: 5px 10px 5px 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.header_button {
|
||||
font-size:15px !important;
|
||||
margin: 7px !important;
|
||||
}
|
||||
|
||||
|
||||
.clear_button {
|
||||
background:#4CAF50;
|
||||
}
|
||||
|
||||
.ris_button {
|
||||
background:#FF9800;
|
||||
}
|
||||
|
||||
.schedule_button {
|
||||
background: #FF0000;
|
||||
}
|
||||
|
||||
.settings {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
||||
transition: 0.3s;
|
||||
padding: 7px 5px 5px 7px;
|
||||
margin: 0px 5px 0px 0px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.material_button {
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
margin: 10px 10px 10px 0px;
|
||||
padding: 10px 10px;
|
||||
border-radius: 10px;
|
||||
font-size: medium;
|
||||
font-style: bold;
|
||||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.course_name_truncate_box {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 80%;
|
||||
color:white;
|
||||
margin:5px;
|
||||
display:inline-block;
|
||||
font-size:large;
|
||||
align-items:center;
|
||||
}
|
||||
|
||||
.settings_divider {
|
||||
margin-bottom: 0px;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.search_button {
|
||||
background-color:white;
|
||||
margin-left: 5px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
.course_list_item_options {
|
||||
display: none;
|
||||
}
|
||||
.import_button {
|
||||
background-color:white;
|
||||
}
|
||||
|
||||
.options_button {
|
||||
background-color:white;
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.settings_icon {
|
||||
color:#FF9800;
|
||||
}
|
||||
|
||||
.course_list_item_time_box {
|
||||
font-weight:bold;
|
||||
padding:10px;
|
||||
margin:0px 5px 0px 15px;
|
||||
font-size:small;
|
||||
}
|
||||
|
||||
.course_list_item_options_button_container {
|
||||
border-radius:0px;
|
||||
}
|
||||
|
||||
.course_list_item_options_buttons{
|
||||
float:right;
|
||||
margin:5px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
float:right;
|
||||
font-size:small;
|
||||
display:inline-block;
|
||||
margin-top:10px;
|
||||
color:white;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.material_button:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
opacity: 0;
|
||||
border-radius: 100%;
|
||||
transform: scale(1, 1) translate(-50%);
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
|
||||
.card:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
opacity: 0;
|
||||
border-radius: 100%;
|
||||
transform: scale(1, 1) translate(-50%);
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
padding-top: 100px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgb(0, 0, 0);
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fefefe;
|
||||
margin: auto;
|
||||
max-height: 85%;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
/* The Close Button */
|
||||
|
||||
.close {
|
||||
color: #aaaaaa;
|
||||
float: right;
|
||||
padding: 5px;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
@keyframes ripple {
|
||||
0% {
|
||||
transform: scale(0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
20% {
|
||||
transform: scale(25, 25);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(40, 40);
|
||||
}
|
||||
}
|
||||
|
||||
.material_button:focus:not(:active)::after {
|
||||
animation: ripple 1s ease-out;
|
||||
}
|
||||
|
||||
|
||||
.card:focus:not(:active)::after {
|
||||
animation: ripple 1s ease-out;
|
||||
}
|
||||
|
||||
|
||||
input {
|
||||
border-radius: 5px;
|
||||
color: rgba(0, 0, 45, 0.48)
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input[type=number]::-webkit-inner-spin-button,
|
||||
input[type=number]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#search-popup {
|
||||
background: white;
|
||||
color: #747474;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
bottom: 42px;
|
||||
right: 20px;
|
||||
padding: 10px;
|
||||
border-radius: inherit;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.select-style {
|
||||
border: 1px solid #979797;
|
||||
margin: 5px 0px;
|
||||
border-radius: 5px;
|
||||
display: none;
|
||||
background: transparent no-repeat 90% 50%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.select-style:after {
|
||||
content: '\e5c5';
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
color: rgba(0, 0, 45, 0.48);
|
||||
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.select-style select {
|
||||
padding: 5px 8px;
|
||||
border: none;
|
||||
color: rgba(0, 0, 45, 0.48);
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
background-image: none;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 120px;
|
||||
word-break: normal;
|
||||
-ms-word-break: normal;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.select-style select:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.class_id_input {
|
||||
display: none;
|
||||
border: 1px solid #979797;
|
||||
border-radius: 5px;
|
||||
margin: 10px 0px;
|
||||
padding: 5px 8px;
|
||||
}
|
||||
|
||||
.class_id_input::placeholder {
|
||||
color: rgba(0, 0, 45, 0.48);
|
||||
}
|
||||
|
||||
.search-button {
|
||||
float: right;
|
||||
font-size: inherit;
|
||||
padding: 7px 11px;
|
||||
margin: 8px 0px;
|
||||
background-color: #FF9800;
|
||||
}
|
||||
|
||||
#import-export-popup {
|
||||
background: white;
|
||||
color: #747474;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
bottom: 42px;
|
||||
right: 10px;
|
||||
border-radius: inherit;
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
|
||||
.simple-menu-option {
|
||||
display: inline-block;
|
||||
color: rgba(0, 0, 45, 0.48);
|
||||
border: none;
|
||||
background-color: white;
|
||||
font-size: 15px;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
padding: 10px 0px 5px 5px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.simple-menu-option i {
|
||||
font-size: 19px;
|
||||
vertical-align: middle;
|
||||
margin-top: 0px;
|
||||
margin-left: 0px;
|
||||
margin-right: 3px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
|
||||
.simple-menu-option:hover {
|
||||
background-color: rgba(177, 175, 175, 0.200);
|
||||
transition-duration: 0.4s;
|
||||
/* color: #FF9800; */
|
||||
}
|
||||
|
||||
.simple-menu-option:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.meta{
|
||||
margin:0;
|
||||
color:#FF9800;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
vertical-align: middle;
|
||||
padding: 7px 5px 5px 7px;
|
||||
margin: 0px 5px 0px 5px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.meta-metric{
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.meta-container{
|
||||
margin: 5px 5px 10px 5px;
|
||||
}
|
||||
|
||||
.input-box{
|
||||
color: rgba(0, 0, 45, 0.48);
|
||||
border: 1px solid #8C8C8C;
|
||||
font-size: 11px;
|
||||
padding: 5px;
|
||||
border-radius: 7px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.input-box::placeholder {
|
||||
color: rgba(0, 0, 45, 0.345);
|
||||
}
|
||||
308
css/styles.css
@@ -1,308 +0,0 @@
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
padding-top: 75px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgb(0, 0, 0);
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fefefe;
|
||||
margin: auto;
|
||||
max-height: 85%;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.loader {
|
||||
border: 10px solid #f3f3f3;
|
||||
border-top: 10px solid #FF9800;
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: none;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.close {
|
||||
color: #aaaaaa;
|
||||
float: right;
|
||||
padding: 5px;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: x-large;
|
||||
font-weight: bold;
|
||||
padding-top: 5px;
|
||||
line-height: 1;
|
||||
padding-left: 5px;
|
||||
margin: 5px 0px 5px 0px;
|
||||
}
|
||||
|
||||
.distButton {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.description {
|
||||
padding: 5px;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
|
||||
.chartloader {
|
||||
position: absolute;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 50px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.profname {
|
||||
margin-left: 5px;
|
||||
padding-bottom: 5px;
|
||||
font-size: medium;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.dateTimePlace {
|
||||
margin-left: 5px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
font-size: smaller;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#chartcontainer {
|
||||
max-width: 100%;
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
#chart {
|
||||
min-width: auto;
|
||||
max-width: 100%;
|
||||
height: 250px;
|
||||
margin: 0 auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.card {
|
||||
transition: 0.3s;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.2), 0 4px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
|
||||
.cardcontainer {
|
||||
padding: 2px 16px;
|
||||
transition: width 300ms ease-in-out, height 300ms ease-in-out;
|
||||
}
|
||||
|
||||
.description {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.topbuttons .material-button {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.rmp-button {
|
||||
|
||||
}
|
||||
|
||||
.ecis-button {
|
||||
|
||||
}
|
||||
|
||||
.textbook-button{
|
||||
|
||||
}
|
||||
|
||||
.material-button {
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
margin: 10px 10px 10px 0px;
|
||||
padding: 10px 10px;
|
||||
border-radius: 10px;
|
||||
font-size: medium;
|
||||
font-style: bold;
|
||||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
|
||||
background: #ff9800;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.material-button:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
opacity: 0;
|
||||
border-radius: 100%;
|
||||
transform: scale(1, 1) translate(-50%);
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
0% {
|
||||
transform: scale(0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
15% {
|
||||
transform: scale(25, 25);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(40, 40);
|
||||
}
|
||||
}
|
||||
|
||||
.material-button:focus:not(:active)::after {
|
||||
animation: ripple 1s ease-out;
|
||||
}
|
||||
|
||||
#snackbar {
|
||||
visibility: hidden;
|
||||
min-width: 250px;
|
||||
margin-left: -200px;
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
padding: 16px;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
left: 50%;
|
||||
bottom: 30px;
|
||||
}
|
||||
|
||||
.descriptionli {
|
||||
padding: 0px 5px 5px 5px;
|
||||
}
|
||||
|
||||
#snackbar.show {
|
||||
visibility: visible;
|
||||
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
||||
animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
||||
}
|
||||
|
||||
#semesters {
|
||||
padding: 5px;
|
||||
margin-right: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#semesters:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
|
||||
.tooltip {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tooltip .tooltiptext {
|
||||
visibility: hidden;
|
||||
background-color: black;
|
||||
background:rgba(1,1,1,0.5);
|
||||
color: #fff;
|
||||
text-align: left;
|
||||
border-radius: 6px;
|
||||
font-size: 10px;
|
||||
max-width: 100px;
|
||||
margin-left: 5px;
|
||||
padding: 5px 10px;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.tooltip:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
|
||||
@-webkit-keyframes fadein {
|
||||
from {
|
||||
bottom: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 30px;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from {
|
||||
bottom: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 30px;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeout {
|
||||
from {
|
||||
bottom: 30px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
from {
|
||||
bottom: 30px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
46
docker-entrypoint.sh
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Define supported modes
|
||||
SUPPORTED_MODES=("build" "zip" "dev")
|
||||
|
||||
# Function to display usage information
|
||||
usage() {
|
||||
echo "Usage: $0 [build|zip|dev]"
|
||||
echo " build: Build the extension"
|
||||
echo " zip: Build and zip the extension"
|
||||
echo " dev: Run in development mode with HMR"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if BUILD_MODE is set, otherwise use the first argument
|
||||
if [ -n "${BUILD_MODE:-}" ]; then
|
||||
mode="$BUILD_MODE"
|
||||
elif [ $# -eq 1 ]; then
|
||||
mode="$1"
|
||||
else
|
||||
usage
|
||||
fi
|
||||
|
||||
# Validate the mode
|
||||
if [[ ! " ${SUPPORTED_MODES[*]} " =~ " ${mode} " ]]; then
|
||||
echo "Error: Invalid mode '${mode}'" >&2
|
||||
usage
|
||||
fi
|
||||
|
||||
# Execute the appropriate command based on the mode
|
||||
case "$mode" in
|
||||
build)
|
||||
echo "Building extension..."
|
||||
exec pnpm run build
|
||||
;;
|
||||
zip)
|
||||
echo "Building and zipping extension..."
|
||||
exec pnpm run zip
|
||||
;;
|
||||
dev)
|
||||
echo "Running in development mode with HMR..."
|
||||
exec pnpm run dev
|
||||
;;
|
||||
esac
|
||||
BIN
docs/UT-Austin-Design-System.pdf
Normal file
0
docs/WebSocket-Implementation-Tutorial.md
Normal file
@@ -1 +0,0 @@
|
||||
theme: jekyll-theme-cayman
|
||||
@@ -1 +0,0 @@
|
||||
["ACC","ADV","ASE","AFR","AFS","ASL","AMS","AHC","ANT","ALD","ARA","ARE","ARI","ARC","AED","ARH","ART","AET","AAS","ANS","AST","BSN","BEN","BCH","BIO","BME","BDP","B A","BAX","BGS","CHE","CH","CHI","C E","CLA","C C","CGS","COM","CLD","CMS","CRP","C L","COE","CSE","C S","CON","CTI","CRW","CDI","EDC","CZ","DAN","DSC","D S","DES","DEV","D B","DRS","DCH","ECO","ELP","EDP","E E","ECE","EER","EMA","ENM","E M","E S","E","ESL","ENS","EVE","EVS","EUP","EUS","FIN","F A","FLU","FR","F H","G E","GRG","GEO","GER","GSD","GOV","GRS","GK","GUI","HAR","H S","HCT","HED","HEB","HIN","HIS","HDF","HDO","H E","HMN","ILA","I","ISP","INF","ITD","I B","IRG","ISL","ITL","ITC","JPN","J S","J","KIN","KOR","LAR","LTC","LAT","LAL","LAS","LAW","LEB","L A","LAH","LIN","MAL","MAN","MIS","MFG","MNS","MKT","MSE","M","M E","MDV","MAS","MEL","MES","M S","MOL","MUS","NSC","N S","NEU","NOR","N","NTR","OBO","OPR","O M","ORI","ORG","PER","PRS","PGE","PGS","PHM","PHL","PED","P S","PHY","PIA","POL","POR","PRC","PSY","P A","PBH","P R","RIM","RTF","R E","R S","RHE","R M","RUS","REE","SAN","SAX","STC","STM","S C","SEL","S S","S W","SOC","SPN","SPC","SED","SLH","STA","SDS","SUS","SWE","TAM","TXA","T D","TRO","TRU","TBA","TUR","T C","UKR","UGS","UDN","URB","URD","UTS","UTL","VIA","VIO","V C","VAS","VOI","WGS","WRT","YID","YOR"]
|
||||
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
@@ -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;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
97
gulpfile.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs';
|
||||
import { dest, series, src } from 'gulp';
|
||||
import { exec } from 'gulp-execa';
|
||||
import zip from 'gulp-zip';
|
||||
import path from 'path';
|
||||
|
||||
const DIST_DIR = 'dist';
|
||||
const PACKAGE_DIR = 'package';
|
||||
const DATABASE_DIR = path.join(DIST_DIR, 'database');
|
||||
|
||||
// Custom log functions
|
||||
const log = message => console.log(chalk.blue(`[${new Date().toTimeString().split(' ')[0]}]`), chalk.white(message));
|
||||
const logWarn = message =>
|
||||
console.warn(
|
||||
chalk.blue(`[${new Date().toTimeString().split(' ')[0]}]`),
|
||||
chalk.yellow(' [WARN]'),
|
||||
chalk.white(message)
|
||||
);
|
||||
const logError = message =>
|
||||
console.error(
|
||||
chalk.blue(`[${new Date().toTimeString().split(' ')[0]}]`),
|
||||
chalk.red(' [ERROR]'),
|
||||
chalk.white(message)
|
||||
);
|
||||
|
||||
// Remove extra database folder
|
||||
function removeExtraDatabaseDir(cb) {
|
||||
fs.rmSync(DATABASE_DIR, { recursive: true, force: true });
|
||||
log('Extra database directory removed.');
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// Zip the dist folder
|
||||
function zipDist() {
|
||||
const packageInfo = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
|
||||
const zipFileName = `${packageInfo.name.replace(/ /g, '-')}-${packageInfo.version}.zip`;
|
||||
|
||||
return src(`${DIST_DIR}/**`, {
|
||||
base: DIST_DIR,
|
||||
encoding: false, // Disable encoding to handle binary files correctly
|
||||
})
|
||||
.pipe(zip(zipFileName))
|
||||
.pipe(dest(PACKAGE_DIR))
|
||||
.on('end', () => log(`Zip file created: ${path.join(PACKAGE_DIR, zipFileName)}`));
|
||||
}
|
||||
|
||||
// Temp fix for CSP on Chrome 130
|
||||
// Manually remove them because there is no option to disable use_dynamic_url on @crxjs/vite-plugin
|
||||
// Force disable use_dynamic_url in manifest.json
|
||||
function forceDisableUseDynamicUrl(cb) {
|
||||
const manifestPath = path.join(DIST_DIR, 'manifest.json');
|
||||
|
||||
if (!fs.existsSync(manifestPath)) {
|
||||
logWarn('manifest.json not found. Skipping modification.');
|
||||
return cb();
|
||||
}
|
||||
|
||||
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
||||
let modified = false;
|
||||
|
||||
manifest.web_accessible_resources.forEach(resource => {
|
||||
if (resource.use_dynamic_url) {
|
||||
delete resource.use_dynamic_url;
|
||||
modified = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (modified) {
|
||||
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
||||
log('use_dynamic_url removed from manifest.json');
|
||||
} else {
|
||||
log('No use_dynamic_url found in manifest.json. No changes made.');
|
||||
}
|
||||
|
||||
cb();
|
||||
}
|
||||
|
||||
// Main build task
|
||||
const zipProdBuild = series(removeExtraDatabaseDir, instrumentWithSentry, zipDist);
|
||||
|
||||
export { forceDisableUseDynamicUrl, zipProdBuild };
|
||||
|
Before Width: | Height: | Size: 19 KiB |
BIN
icons/icon16.png
|
Before Width: | Height: | Size: 18 KiB |
BIN
icons/icon32.png
|
Before Width: | Height: | Size: 18 KiB |
BIN
icons/icon48.png
|
Before Width: | Height: | Size: 17 KiB |
BIN
images/UTRP-Demo.gif
Normal file
|
After Width: | Height: | Size: 5.0 MiB |
BIN
images/UTRP_Social-Preview_Prod.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
7
images/UTRP_Social-Preview_Prod.svg
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
196
js/Template.js
@@ -1,196 +0,0 @@
|
||||
class Template {}
|
||||
|
||||
Template.Main = class {
|
||||
static modal() {
|
||||
return `<div class=modal id=myModal>
|
||||
<div class=modal-content>
|
||||
<span class=close>×</span>
|
||||
<div class=card>
|
||||
<div class=cardcontainer>
|
||||
<h2 class=title id="title">Computer Fluency (C S 302)</h2>
|
||||
<h2 class=profname id="profname">with <a id="professor_link">Bruce Porter</a></h2>
|
||||
<div id="topbuttons" class=topbuttons>
|
||||
<button class=material-button id="rateMyProf" style="background: #4CAF50;"> RMP </button>
|
||||
<button class=material-button id="eCIS" style="background: #CDDC39;"> eCIS </button>
|
||||
<button class=material-button id="textbook" style="background: #FFC107;"> Textbook </button>
|
||||
<button class=material-button id="Syllabi"> Past Syllabi </button>
|
||||
<button class=material-button id="saveCourse" value="add" style="background: #F44336;"> Save Course +</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=card>
|
||||
<div class=cardcontainer style="">
|
||||
<div class="chartloader">
|
||||
<div class="loader" id='descload'></div>
|
||||
</div>
|
||||
<ul class=description id="description" style="list-style-type:disc"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class=card style='text-align:center'>
|
||||
<select id="semesters" style='text-align-last:center;color:#666666;fill:#666666;'>
|
||||
</select>
|
||||
<div class="chartloader">
|
||||
<div class="loader" id='chartload'></div>
|
||||
</div>
|
||||
<div id="chartcontainer" class=cardcontainer>
|
||||
<div id=chart></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
static extension_button() {
|
||||
return `<td data-th="Plus"><input type="image" class="distButton" id="distButton" width="20" height="20" src='${chrome.extension.getURL("images/disticon.png")}'/></td>`;
|
||||
}
|
||||
};
|
||||
Template.Catalog = class {
|
||||
static loading() {
|
||||
return `<div style="text-align:center">
|
||||
<div class="loader" id='loader'></div>
|
||||
<br>
|
||||
<h1 id="nextlabel"style="color: #FF9800;display:none;">Loading Courses</h1>
|
||||
<h1 id="retrylabel"style="color: #F44336;display:none;">Failed to Load Courses</h1>
|
||||
<br>
|
||||
<button class=material-button id="retry" style="background: #F44336;display:none;">Retry</button>
|
||||
</div>`;
|
||||
}
|
||||
};
|
||||
Template.UTPlanner = class {
|
||||
static modal() {
|
||||
return `<div class=modal id=myModal>
|
||||
<div class=modal-content>
|
||||
<span class=close>×</span>
|
||||
<div class=card>
|
||||
<div class=cardcontainer>
|
||||
<h2 class=title id="title">Computer Fluency (C S 302)</h2>
|
||||
<h2 class=profname id="profname" style="margin-bottom:0px;">with Bruce Porter</h2>
|
||||
<div id="topbuttons" class=topbuttons>
|
||||
<button class=material-button id="moreInfo" style="background: #2196F3;"> More Info </button>
|
||||
<button class=material-button id="textbook" style="background: #FFC107;"> Textbook </button>
|
||||
<button class=material-button id="Syllabi"> Past Syllabi </button>
|
||||
<button class=material-button id="saveCourse" value="add" style="background: #F44336;opacity:.4;"> Unable to Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=card style='text-align:center'>
|
||||
<select id="semesters" style='text-align-last:center;color:#666666;fill:#666666;'>
|
||||
</select>
|
||||
<div class="chartloader">
|
||||
<div class="loader" id='chartload'></div>
|
||||
</div>
|
||||
<div id="chartcontainer" class=cardcontainer>
|
||||
<div id=chart></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
};
|
||||
Template.Calendar = class {
|
||||
static line(line) {
|
||||
let { days, start_time, end_time, location_link, location_full } = line;
|
||||
return `<p class='time' style='font-size:large;'>
|
||||
<span style='display:inline-block;'>${days}:</span>
|
||||
<span style='margin-left:10px;display:inline-block;text-align:center;'>${start_time} to ${end_time}</span>
|
||||
<span style='float:right;display:inline-block;text-align:right;width: 25%;'>
|
||||
<a target='_blank' style='color:#3c87a3;text-decoration:none;'href='${location_link}'>${location_full}</a>
|
||||
</span>
|
||||
</p>`;
|
||||
}
|
||||
static modal() {
|
||||
return `<div id="myModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close">×</span>
|
||||
<div class="card">
|
||||
<div id="colorStrip" style="height:10px;"></div>
|
||||
<div class="cardcontainer">
|
||||
<div id='header'>
|
||||
<div style="display:flex;">
|
||||
<h2 id="classname">Classname</h2>
|
||||
</div>
|
||||
<p id="prof">Prof</p>
|
||||
</div>
|
||||
<button id="info" class="matbut" style="font-size:medium; margin-right: auto; margin-left:auto; background: #2196F3;">More Info</button>
|
||||
<button id="register" class="matbut" style="font-size:medium; margin-right: auto; margin-left:10px; background: #4CAF50;">Register</button>
|
||||
<button id="remove" class="matbut" style="font-size:medium;margin:10px;background: #FF0000;">Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
};
|
||||
Template.Popup = class {
|
||||
static list_item(i, list_tile_color, unique, department, number, profname, list_sub_color, line) {
|
||||
return `<li id='${i}' class='course_list_item'>
|
||||
<div class='card course_list_card'>
|
||||
<div class='container' style='background:${list_tile_color}'>
|
||||
<button class='copy_button' title='Copy Unique #' value='${unique}'>
|
||||
<i id='copyicon' class="material-icons copy_button_icon">content_copy</i>
|
||||
</button>
|
||||
<h4 class='course_name_truncate_box'>
|
||||
<b>${department} ${number} <span class='course_list_item_subtext'> with ${profname} (${unique})</span></b>
|
||||
</h4>
|
||||
<p id='arrow' class='arrow'>►</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id='moreInfo' class='course_list_item_options'>
|
||||
<p style='background-color:${list_sub_color};' class='course_list_item_time_box'>${line}</p>
|
||||
<div id='infoButtons' class='course_list_item_options_button_container'>
|
||||
<button class='material_button course_list_item_options_buttons remove_button' id='listRemove'>Remove</button>
|
||||
<button class='material_button course_list_item_options_buttons register_button' id='register'>Register</button>
|
||||
<button class='material_button course_list_item_options_buttons more_info_button' id='listMoreInfo'>More Info</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
static conflict_message(conflict_message) {
|
||||
return `<p id='conflict' class='conflict_message'>${conflict_message}</>`;
|
||||
}
|
||||
|
||||
static line(line) {
|
||||
let { days, start_time, end_time, location_link, location_full } = line;
|
||||
|
||||
return `<span class='time_line_days'>${days}:</span>
|
||||
<span class='time_line_hours'>${start_time} to ${end_time}</span>
|
||||
<span class='time_line_location'>
|
||||
<a target='_blank' class= 'time_line_location_link' href='${location_link}'>${location_full}</a>
|
||||
</span>
|
||||
<br>`;
|
||||
}
|
||||
};
|
||||
Template.Import = class {
|
||||
static import_button() {
|
||||
return `<button class='material-button' id='import' style='margin:15px 0px;'>${Text.button_text_default}</button><br>`;
|
||||
}
|
||||
|
||||
static waitlist_import_button() {
|
||||
return `<button class='material-button' id='import_waitlist' style='margin:0px'>${Text.waitlist_button_text_default}</button><br>`;
|
||||
}
|
||||
|
||||
static store_waitlist_message() {
|
||||
return `<h1 id="nextlabel"style="color: #FF9800;display:none;"></h1>`;
|
||||
}
|
||||
};
|
||||
|
||||
Template.Options = class {
|
||||
static options_row(key, enabled) {
|
||||
let button_text = enabled ? "Turn Off" : "Turn On";
|
||||
let button_color = enabled ? Colors.closed : Colors.open;
|
||||
let label_text = capitalizeString(key.replace(/([A-Z]+)*([A-Z][a-z])/g, "$1 $2"));
|
||||
return `<h2 style="padding: 5px 16px 5px 16px; font-weight: normal;display: inline-block;text-align:left;">
|
||||
${label_text}
|
||||
</h2>
|
||||
<button id="${key}" value=${enabled} class="material-button" style="display:inline-block;font-size:medium; float:right; background:${button_color}">
|
||||
${button_text}
|
||||
</button>
|
||||
<br>`;
|
||||
}
|
||||
|
||||
static contributor_card(username, name, image_url, profile_url) {
|
||||
return `<div class='card contributor-card' id="${username}" data-url="${profile_url}">
|
||||
<img class='contributor-image' src="${image_url}"></img>
|
||||
${name ? `<p class='contributor-name'>${name}</p>` : ""}
|
||||
<p class='contributor-username'>${username}</p>
|
||||
</div>`;
|
||||
}
|
||||
};
|
||||
487
js/background.js
@@ -1,487 +0,0 @@
|
||||
console.log(`UT Registration Plus background page: ${window.location.href}`);
|
||||
var grades; // caching the grades database in memory for faster queries
|
||||
var current_semesters = {};
|
||||
var departments = [];
|
||||
var should_open = false; // toggled flag for automatically opening popup on new pages when 'more info' hit
|
||||
|
||||
// these are the default options that the extension currently supports
|
||||
const default_options = {
|
||||
loadAll: true,
|
||||
courseConflictHighlight: true,
|
||||
storeWaitlist: true,
|
||||
};
|
||||
|
||||
onStartup();
|
||||
|
||||
function onStartup() {
|
||||
updateBadge(true);
|
||||
loadDataBase();
|
||||
getCurrentSemesters();
|
||||
getCurrentDepartments();
|
||||
}
|
||||
|
||||
/* Handle messages and their commands from content and popup scripts*/
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, response) {
|
||||
switch (request.command) {
|
||||
case "courseStorage":
|
||||
if (request.action == "add") {
|
||||
add(request, sender, response);
|
||||
}
|
||||
if (request.action == "remove") {
|
||||
remove(request, sender, response);
|
||||
}
|
||||
break;
|
||||
case "isSingleConflict":
|
||||
isSingleConflict(request.dtarr, request.unique, response);
|
||||
break;
|
||||
case "checkConflicts":
|
||||
checkConflicts(response);
|
||||
break;
|
||||
case "updateBadge":
|
||||
updateBadge();
|
||||
break;
|
||||
case "updateStatus":
|
||||
updateStatus(response);
|
||||
break;
|
||||
case "alreadyContains":
|
||||
alreadyContains(request.unique, response);
|
||||
break;
|
||||
case "updateCourseList":
|
||||
updateTabs();
|
||||
break;
|
||||
case "gradesQuery":
|
||||
executeQuery(request.query, response);
|
||||
break;
|
||||
case "currentSemesters":
|
||||
response({ semesters: current_semesters });
|
||||
getCurrentSemesters();
|
||||
break;
|
||||
case "currentDepartments":
|
||||
response({ departments: departments });
|
||||
break;
|
||||
case "setOpen":
|
||||
should_open = true;
|
||||
chrome.tabs.create({ url: request.url });
|
||||
break;
|
||||
case "shouldOpen":
|
||||
response({ open: should_open });
|
||||
should_open = false;
|
||||
break;
|
||||
case "getOptionsValue":
|
||||
getOptionsValue(request.key, response);
|
||||
break;
|
||||
case "setOptionsValue":
|
||||
setOptionsValue(request.key, request.value, response);
|
||||
break;
|
||||
default:
|
||||
const xhr = new XMLHttpRequest();
|
||||
const method = request.method ? request.method.toUpperCase() : "GET";
|
||||
xhr.open(method, request.url, true);
|
||||
console.log(request);
|
||||
xhr.onload = () => {
|
||||
console.log(xhr.responseUrl);
|
||||
response(xhr.responseText);
|
||||
};
|
||||
xhr.onerror = () => response(xhr.statusText);
|
||||
if (method == "POST") {
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
}
|
||||
xhr.send(request.data);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
/* Initially set the course data in storage */
|
||||
chrome.runtime.onInstalled.addListener(function (details) {
|
||||
if (details.reason == "install") {
|
||||
setDefaultOptions();
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
if (!data.savedCourses) {
|
||||
chrome.storage.sync.set({
|
||||
savedCourses: [],
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (details.reason == "update") {
|
||||
// if there's been an update, call setDefaultOptions in case their settings have gotten wiped
|
||||
setDefaultOptions();
|
||||
console.log("updated");
|
||||
}
|
||||
});
|
||||
|
||||
chrome.storage.onChanged.addListener(function (changes) {
|
||||
for (key in changes) {
|
||||
if (key === "savedCourses") {
|
||||
updateBadge(false, changes.savedCourses.newValue); // update the extension popup badge whenever the savedCourses have been changed
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// get the value of an option if it exists
|
||||
function getOptionsValue(key, sendResponse) {
|
||||
chrome.storage.sync.get("options", function (data) {
|
||||
if (!data.options) {
|
||||
setDefaultOptions();
|
||||
} else {
|
||||
sendResponse({
|
||||
value: data.options[key],
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// set the value of an option if it exists
|
||||
function setOptionsValue(key, value, sendResponse) {
|
||||
chrome.storage.sync.get("options", function (data) {
|
||||
let new_options = data.options;
|
||||
if (!data.options) {
|
||||
// if there are no options set, set the defaults
|
||||
setDefaultOptions();
|
||||
new_options = default_options;
|
||||
}
|
||||
new_options[key] = value;
|
||||
chrome.storage.sync.set(
|
||||
{
|
||||
options: new_options,
|
||||
},
|
||||
function () {
|
||||
sendResponse({
|
||||
value: new_options[key],
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// set the default options if the options haven't been set before
|
||||
function setDefaultOptions() {
|
||||
chrome.storage.sync.get("options", function (data) {
|
||||
if (!data.options) {
|
||||
chrome.storage.sync.set(
|
||||
{
|
||||
options: default_options,
|
||||
},
|
||||
function () {
|
||||
console.log("default options:", default_options);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function getCurrentSemesters() {
|
||||
let webData;
|
||||
if(Object.keys(current_semesters).length > 0) {
|
||||
chrome.storage.local.set({
|
||||
semesterCache: current_semesters
|
||||
});
|
||||
}
|
||||
async function goFetch(linkend="") {
|
||||
console.log("lk " + linkend)
|
||||
return fetch("https://registrar.utexas.edu/schedules/" + linkend)
|
||||
.then((response) => {
|
||||
return response.text()
|
||||
.then((data) => {
|
||||
return data;
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
await goFetch().then((data) => {webData = data});
|
||||
if(webData == null) {
|
||||
webData = ""
|
||||
}
|
||||
let arr = webData.split("\n");
|
||||
let i = 0
|
||||
for(let row=0; row<arr.length; row++) {
|
||||
let currentRow = arr[row]
|
||||
if(currentRow.startsWith('<li><a href="https://registrar.utexas.edu/schedules/') && currentRow[52] != "a") {
|
||||
let newWebData;
|
||||
|
||||
// let start = currentRow.indexOf('Schedule">')+10;
|
||||
let start = Math.max(currentRow.lastIndexOf('Summer'), Math.max(currentRow.lastIndexOf('Spring'), currentRow.lastIndexOf('Fall')))
|
||||
let end = currentRow.indexOf('</a></li>');
|
||||
console.log(currentRow)
|
||||
console.log(start + " " + end)
|
||||
let name = currentRow.substring(start,end);
|
||||
console.log("my name: " + name)
|
||||
|
||||
let num = currentRow.indexOf('"https://registrar.utexas.edu/schedules/">')+53;
|
||||
let numend = currentRow.indexOf('" target');
|
||||
let short_sem_num = currentRow.substring(num,numend);
|
||||
current_semesters[name] = "code";
|
||||
|
||||
await goFetch(short_sem_num).then((data) => {newWebData = data});
|
||||
arr2 = newWebData.split("\n")
|
||||
|
||||
for(let row2=0; row2<arr2.length; row2++) {
|
||||
if(arr2[row2].startsWith('<div class="gobutton"><a href="')) {
|
||||
let start2 = arr2[row2].indexOf('<div class="gobutton"><a href="')+31;
|
||||
let end2 = arr2[row2].indexOf('" target="');
|
||||
var scheduleLink = arr2[row2].substring(start2,end2);
|
||||
var sem_num = scheduleLink.substring(scheduleLink.lastIndexOf("/") + 1).trim();
|
||||
if (current_semesters[name] != sem_num) {
|
||||
current_semesters[name] = sem_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// use the utexas review api for getting the list of departments
|
||||
function getCurrentDepartments() {
|
||||
$.get("https://raw.githubusercontent.com/sghsri/UT-Registration-Plus/master/docs/departments.json", function (response) {
|
||||
if (response) {
|
||||
departments = JSON.parse(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// update the badge text to reflect the new changes
|
||||
function updateBadge(first, new_changes) {
|
||||
if (new_changes) {
|
||||
updateBadgeText(first, new_changes);
|
||||
} else {
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
let courses = data.savedCourses;
|
||||
updateBadgeText(first, courses);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// update the badge text to show the number of courses that have been saved by the user
|
||||
function updateBadgeText(first, courses) {
|
||||
let badge_text = courses.length > 0 ? `${courses.length}` : "";
|
||||
let flash_time = !first ? 200 : 0;
|
||||
chrome.browserAction.setBadgeText({
|
||||
text: badge_text,
|
||||
});
|
||||
if (!first) {
|
||||
// if isn't the first install of the extension, flash the badge to bring attention to it
|
||||
chrome.browserAction.setBadgeBackgroundColor({
|
||||
color: Colors.badge_flash,
|
||||
});
|
||||
}
|
||||
setTimeout(function () {
|
||||
chrome.browserAction.setBadgeBackgroundColor({
|
||||
color: Colors.badge_default,
|
||||
});
|
||||
}, flash_time);
|
||||
}
|
||||
|
||||
/* Find all the conflicts in the courses and send them out/ if there is even a conflict*/
|
||||
function checkConflicts(sendResponse) {
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
var conflicts = [];
|
||||
var courses = data.savedCourses;
|
||||
for (let i = 0; i < courses.length; i++) {
|
||||
for (let j = i + 1; j < courses.length; j++) {
|
||||
let course_a = courses[i];
|
||||
let course_b = courses[j];
|
||||
if (isConflict(course_a.datetimearr, course_b.datetimearr)) conflicts.push([course_a, course_b]);
|
||||
}
|
||||
}
|
||||
sendResponse({
|
||||
isConflict: conflicts.length !== 0,
|
||||
between: conflicts.length ? conflicts : undefined,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* Find if the course at unique and with currdatearr is contained in the saved courses and if it conflicts with any other courses*/
|
||||
function isSingleConflict(currdatearr, unique, sendResponse) {
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
var courses = data.savedCourses;
|
||||
var conflict_list = [];
|
||||
var conflict = false;
|
||||
var contains = false;
|
||||
for (let i = 0; i < courses.length; i++) {
|
||||
let course = courses[i];
|
||||
if (isConflict(currdatearr, course.datetimearr)) {
|
||||
conflict = true;
|
||||
conflict_list.push(course);
|
||||
}
|
||||
if (!contains && isSameCourse(course, unique)) {
|
||||
contains = true;
|
||||
}
|
||||
}
|
||||
sendResponse({
|
||||
isConflict: conflict,
|
||||
alreadyContains: contains,
|
||||
conflictList: conflict_list,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* Check if conflict between two date-time-arrs*/
|
||||
function isConflict(adtarr, bdtarr) {
|
||||
for (var i = 0; i < adtarr.length; i++) {
|
||||
var current_day = adtarr[i][0];
|
||||
var current_times = adtarr[i][1];
|
||||
for (var j = 0; j < bdtarr.length; j++) {
|
||||
var next_day = bdtarr[j][0];
|
||||
var next_times = bdtarr[j][1];
|
||||
if (next_day == current_day) {
|
||||
if (current_times[0] < next_times[1] && current_times[1] > next_times[0]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add the requested course to the storage*/
|
||||
function add(request, sender, sendResponse) {
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
var courses = data.savedCourses;
|
||||
if (!contains(courses, request.course.unique)) {
|
||||
courses.push(request.course);
|
||||
console.log(courses);
|
||||
chrome.storage.sync.set({
|
||||
savedCourses: courses,
|
||||
});
|
||||
}
|
||||
sendResponse({
|
||||
done: "Added: (" + request.course.unique + ") " + request.course.coursename,
|
||||
label: "Remove Course -",
|
||||
value: "remove",
|
||||
});
|
||||
});
|
||||
}
|
||||
/* Find and Remove the requested course from the storage*/
|
||||
function remove(request, sender, sendResponse) {
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
var courses = data.savedCourses;
|
||||
console.log(courses);
|
||||
var index = 0;
|
||||
while (index < courses.length && courses[index].unique != request.course.unique) {
|
||||
index++;
|
||||
}
|
||||
courses.splice(index, 1);
|
||||
chrome.storage.sync.set({
|
||||
savedCourses: courses,
|
||||
});
|
||||
sendResponse({
|
||||
done: "Removed: (" + request.course.unique + ") " + request.course.coursename,
|
||||
label: "Add Course +",
|
||||
value: "add",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* Find if the unique is already contained within the storage*/
|
||||
function alreadyContains(unique, sendResponse) {
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
var courses = data.savedCourses;
|
||||
sendResponse({
|
||||
alreadyContains: contains(courses, unique),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// find if a course with the current unique number exists in the user's saved courses
|
||||
function contains(courses, unique) {
|
||||
var i = 0;
|
||||
while (i < courses.length) {
|
||||
if (isSameCourse(courses[i], unique)) {
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// does it have the same unique number as provided
|
||||
function isSameCourse(course, unique) {
|
||||
return course.unique == unique;
|
||||
}
|
||||
|
||||
// send a message to every tab open to updateit's course list (and thus recalculate its conflicts highlighting)
|
||||
function updateTabs() {
|
||||
chrome.tabs.query({}, function (tabs) {
|
||||
for (var i = 0; i < tabs.length; i++) {
|
||||
chrome.tabs.sendMessage(tabs[i].id, {
|
||||
command: "updateCourseList",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// const UPDATE_INTERVAL = 1000 * 60 * 16;
|
||||
// setInterval(updateStatus, UPDATE_INTERVAL);
|
||||
// // updateStatus();
|
||||
|
||||
// function updateStatus(sendResponse) {
|
||||
// chrome.storage.sync.get("savedCourses", function (data) {
|
||||
// var courses = data.savedCourses;
|
||||
// var no_change = true;
|
||||
// for (let i = 0; i < courses.length; i++) {
|
||||
// try {
|
||||
// let c = courses[i];
|
||||
// let old_status = c.status;
|
||||
// let old_link = c.link;
|
||||
// $.ajax({
|
||||
// url: old_link,
|
||||
// success: function (result) {
|
||||
// if (result) {
|
||||
// console.log(result);
|
||||
// var object = $("<div/>").html(result).contents();
|
||||
// let new_status = object.find('[data-th="Status"]').text();
|
||||
// let register_link = object.find('td[data-th="Add"] a');
|
||||
// if (register_link) register_link = register_link.attr("href");
|
||||
// var haschanged = new_status == old_status && register_link == old_link;
|
||||
// if (!haschanged) console.log(c.unique + " updated from " + old_status + " to " + new_status + " and " + old_link + " to " + register_link);
|
||||
// no_change &= haschanged;
|
||||
// c.registerlink = register_link;
|
||||
// c.status = new_status;
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
// } catch (e) {
|
||||
// console.log(e);
|
||||
// console.log("Not logged into UT Coursebook. Could not update class statuses.");
|
||||
// }
|
||||
// }
|
||||
// if (!no_change) {
|
||||
// chrome.storage.sync.set({
|
||||
// savedCourses: courses,
|
||||
// });
|
||||
// console.log("updated status");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// execute a query on the grades database
|
||||
function executeQuery(query, sendResponse) {
|
||||
var res = grades.exec(query)[0];
|
||||
sendResponse({
|
||||
data: res,
|
||||
});
|
||||
}
|
||||
|
||||
/* Load the database*/
|
||||
function loadDataBase() {
|
||||
sql = window.SQL;
|
||||
loadBinaryFile("grades.db", function (data) {
|
||||
var sqldb = new SQL.Database(data);
|
||||
grades = sqldb;
|
||||
});
|
||||
}
|
||||
/* load the database from file */
|
||||
function loadBinaryFile(path, success) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", chrome.extension.getURL(path), true);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.onload = function () {
|
||||
var data = new Uint8Array(xhr.response);
|
||||
var arr = new Array();
|
||||
for (var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
|
||||
success(arr.join(""));
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
291
js/calendar.js
@@ -1,291 +0,0 @@
|
||||
var color_counter = 0;
|
||||
var {
|
||||
calendar_fade_time,
|
||||
button_delay
|
||||
} = Timing;
|
||||
|
||||
|
||||
|
||||
var saved_courses = [];
|
||||
var curr_course = {}
|
||||
|
||||
$("#calendar").after(Template.Calendar.modal());
|
||||
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
// Iterate through each saved course and add to 'event'
|
||||
saved_courses = data.savedCourses;
|
||||
console.log(saved_courses);
|
||||
let event_source = buildEventSource(saved_courses);
|
||||
|
||||
$("#calendar").fullCalendar({
|
||||
editable: false, // Don't allow editing of events
|
||||
handleWindowResize: true,
|
||||
weekends: false, // will hide Saturdays and Sundays
|
||||
slotDuration: "00:30:00", // 15 minute intervals on vertical column
|
||||
slotEventOverlap: false, // No overlapping between events
|
||||
defaultView: "agendaWeek", // Only show week view
|
||||
header: false, // Hide buttons/titles
|
||||
minTime: "08:00:00", // Start time
|
||||
maxTime: "21:00:01", // End time
|
||||
columnHeaderFormat: "ddd", // Only show day of the week names
|
||||
displayEventTime: true, // Display event time
|
||||
allDaySlot: false,
|
||||
Duration: {
|
||||
hours: 1
|
||||
},
|
||||
height: 'auto',
|
||||
events: event_source,
|
||||
slotLabelFormat: [
|
||||
'h:mm A' // lower level of text
|
||||
],
|
||||
eventRender: function (event, element, view) {
|
||||
$(element).css("padding", "5px").css("margin-bottom", "5px");
|
||||
},
|
||||
eventClick: function (data, event, view) {
|
||||
displayModal(data)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function displayModal(data) {
|
||||
$("#myModal").fadeIn(calendar_fade_time);
|
||||
$("#colorStrip").css('background-color', data.color);
|
||||
curr_course = saved_courses[data.index];
|
||||
setUpModal()
|
||||
}
|
||||
|
||||
function setUpModal() {
|
||||
let {
|
||||
coursename,
|
||||
unique,
|
||||
datetimearr,
|
||||
profname,
|
||||
status,
|
||||
registerlink
|
||||
} = curr_course;
|
||||
$("#classname").html(`${coursename} <span style='font-size:small'>(${unique})</span>`);
|
||||
buildTimeTitle(datetimearr);
|
||||
$("#prof").html(`with <span style='font-weight:bold;'>${capitalizeString(profname)}</span>`);
|
||||
setRegisterButton(status, registerlink)
|
||||
}
|
||||
|
||||
function setRegisterButton(status, registerlink) {
|
||||
if (canNotRegister(status, registerlink))
|
||||
$("#register").text("Can't Register").css("background-color", Colors.closed);
|
||||
else if (status.includes("waitlisted"))
|
||||
$("#register").text("Join Waitlist").css("background-color", Colors.waitlisted);
|
||||
else
|
||||
$("#register").text("Register").css("background-color", Colors.open);
|
||||
}
|
||||
|
||||
function buildTimeTitle(datetimearr) {
|
||||
$('#timelines').remove();
|
||||
var arr = convertDateTimeArrToLine(datetimearr)
|
||||
var output = "";
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
let line = arr[i];
|
||||
output += Template.Calendar.line(line);
|
||||
}
|
||||
$("#header").after(`<div id='timelines'>${output}</div`);
|
||||
}
|
||||
|
||||
|
||||
// Iterate through each saved course and add to 'event'
|
||||
function buildEventSource(saved_courses) {
|
||||
color_counter = 0;
|
||||
let event_source = [];
|
||||
var hours = 0;
|
||||
for (let i = 0; i < saved_courses.length; i++) {
|
||||
let {
|
||||
coursename,
|
||||
datetimearr
|
||||
} = saved_courses[i];
|
||||
let number = separateCourseNameParts(coursename).number;
|
||||
let class_length = parseInt(number.charAt(0));
|
||||
let multi_semester_code = number.slice(-1);
|
||||
if (["A","B"].includes(multi_semester_code)) {
|
||||
hours += Math.floor(class_length/2);
|
||||
} else if (["X","Y","Z"].includes(multi_semester_code)) {
|
||||
hours += Math.floor(class_length/3);
|
||||
} else {
|
||||
hours += class_length;
|
||||
}
|
||||
for (let j = 0; j < datetimearr.length; j++) {
|
||||
let session = datetimearr[j]; // One single session for a class
|
||||
let event_obj = setEventForSection(session, color_counter, i);
|
||||
event_source.push(event_obj);
|
||||
}
|
||||
color_counter++;
|
||||
}
|
||||
displayMetaData(hours, saved_courses);
|
||||
return event_source;
|
||||
}
|
||||
|
||||
function displayMetaData(hours, saved_courses) {
|
||||
$("#hours").text(hours + " Hours");
|
||||
$("#num").text(saved_courses.length + " Courses");
|
||||
}
|
||||
|
||||
//create the event object for every section
|
||||
function setEventForSection(session, colorCounter, i) {
|
||||
let full_day = days.get(session[0]);
|
||||
let course = saved_courses[i];
|
||||
let {
|
||||
coursename,
|
||||
profname,
|
||||
} = course;
|
||||
let {
|
||||
department,
|
||||
number
|
||||
} = separateCourseNameParts(coursename)
|
||||
beg_day = calculateBeginningDate(full_day)
|
||||
start_date = formatCalculateDate(beg_day, full_day, session[1][0]);
|
||||
end_date = formatCalculateDate(beg_day, full_day, session[1][1]);
|
||||
|
||||
event_obj = {
|
||||
title: `${department}-${number} with ${capitalizeString(profname)}`,
|
||||
start: start_date,
|
||||
end: end_date,
|
||||
color: Colors.material_colors[colorCounter],
|
||||
building: session[2],
|
||||
index: i,
|
||||
allday: false
|
||||
};
|
||||
return event_obj;
|
||||
}
|
||||
|
||||
function formatCalculateDate(beg_day, full_day, hour) {
|
||||
return beg_day + moment().day(full_day)._d.toString().split(" ")[2] + "T" + hour + ":00";
|
||||
}
|
||||
|
||||
function calculateBeginningDate(full_day) {
|
||||
var year = moment().day(full_day)._d.toString().split(" ")[3];
|
||||
var month_num = moment(moment().day(full_day)._d.toString().split(" ")[1], "MMM").format('MM');
|
||||
return `${year}-${month_num}-`;
|
||||
}
|
||||
|
||||
function updateCalendar() {
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
saved_courses = data.savedCourses
|
||||
let event_source = buildEventSource(saved_courses);
|
||||
$('#calendar').fullCalendar('removeEventSources');
|
||||
$("#calendar").fullCalendar('addEventSource', event_source, true);
|
||||
});
|
||||
}
|
||||
chrome.runtime.onMessage.addListener(
|
||||
function (request, sender, sendResponse) {
|
||||
if (request.command == "updateCourseList" || request.command == "courseAdded") {
|
||||
updateCalendar();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
$("#info").click(() => {
|
||||
openMoreInfoWithOpenModal(curr_course.link);
|
||||
});
|
||||
|
||||
|
||||
$("#save").click(() => {
|
||||
takePicture();
|
||||
});
|
||||
|
||||
|
||||
$("#clear").click(() => {
|
||||
/*Clear the list and the storage of courses*/
|
||||
chrome.storage.sync.set({
|
||||
savedCourses: []
|
||||
});
|
||||
updateAllTabsCourseList();
|
||||
updateCalendar();
|
||||
});
|
||||
|
||||
|
||||
$("#remove").click(() => {
|
||||
setTimeout(() => {
|
||||
chrome.runtime.sendMessage({
|
||||
command: "courseStorage",
|
||||
course: curr_course,
|
||||
action: "remove"
|
||||
}, function () {
|
||||
$("#myModal").fadeOut(calendar_fade_time);
|
||||
updateCalendar();
|
||||
updateAllTabsCourseList();
|
||||
});
|
||||
}, button_delay);
|
||||
});
|
||||
|
||||
|
||||
$("#register").click(function () {
|
||||
let {
|
||||
registerlink,
|
||||
status
|
||||
} = curr_course;
|
||||
if (!canNotRegister(status, registerlink)) {
|
||||
setTimeout(() => {
|
||||
window.open(registerlink);
|
||||
}, button_delay);
|
||||
}
|
||||
});
|
||||
|
||||
$("#export").click(function () {
|
||||
var cal = ics();
|
||||
var calendarEvents = $('#calendar').fullCalendar('clientEvents');
|
||||
for (i in calendarEvents) {
|
||||
var event = calendarEvents[i];
|
||||
buildICSFile(cal, event);
|
||||
}
|
||||
cal.download("My_Course_Calendar");
|
||||
});
|
||||
|
||||
|
||||
function buildICSFile(cal, event) {
|
||||
let {
|
||||
title,
|
||||
start,
|
||||
end,
|
||||
building
|
||||
} = event;
|
||||
let class_name = title.split('with')[0];
|
||||
let description = `with ${title.split('with')[1]}`;
|
||||
let time = start._d.toUTCString();
|
||||
cal.addEvent(class_name, description, building, start._i, end._i, {
|
||||
rrule: `RRULE:FREQ=WEEKLY;BYDAY=${time.substring(0, time.indexOf(",") - 1).toUpperCase()};INTERVAL=1`
|
||||
});
|
||||
}
|
||||
|
||||
function takePicture() {
|
||||
var width = $("#calendar").width() * window.devicePixelRatio;
|
||||
var height = $("#calendar").height() * window.devicePixelRatio;
|
||||
let cropper = document.createElement('canvas').getContext('2d');
|
||||
html2canvas(document.querySelector("#calendar"), Export.png_options).then(c => {
|
||||
cropper.canvas.width = width;
|
||||
cropper.canvas.height = height;
|
||||
cropper.drawImage(c, 0, 0);
|
||||
var a = document.createElement('a');
|
||||
a.href = cropper.canvas.toDataURL("image/png");
|
||||
a.download = 'mySchedule.png';
|
||||
a.click();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*Close Modal when hit escape*/
|
||||
$(document).keydown((e) => {
|
||||
if (e.keyCode == 27) {
|
||||
$("#myModal").fadeOut(calendar_fade_time);
|
||||
}
|
||||
});
|
||||
|
||||
$('.close').click(function () {
|
||||
close();
|
||||
});
|
||||
$('#myModal').click(function (event) {
|
||||
if (event.target.id == 'myModal') {
|
||||
close();
|
||||
}
|
||||
});
|
||||
|
||||
function close() {
|
||||
$("#myModal").fadeOut(calendar_fade_time);
|
||||
}
|
||||
87
js/config.js
@@ -1,87 +0,0 @@
|
||||
class Timing {}
|
||||
Timing.fade_time = 100;
|
||||
Timing.calendar_fade_time = 100;
|
||||
Timing.button_delay = 75;
|
||||
|
||||
class Colors {}
|
||||
Colors.material_colors = [
|
||||
"#4CAF50",
|
||||
"#CDDC39",
|
||||
"#FFC107",
|
||||
"#2196F3",
|
||||
"#F57C00",
|
||||
"#9C27B0",
|
||||
"#FF5722",
|
||||
"#673AB7",
|
||||
"#FF5252",
|
||||
"#E91E63",
|
||||
"#009688",
|
||||
"#00BCD4",
|
||||
"#4E342E",
|
||||
"#424242",
|
||||
"#9E9E9E",
|
||||
];
|
||||
Colors.open = "#4CAF50";
|
||||
Colors.waitlisted = "#FF9800";
|
||||
Colors.closed = "#FF5722";
|
||||
Colors.no_status = "#607D8B";
|
||||
|
||||
Colors.open_light = "#C8E6C9";
|
||||
Colors.waitlisted_light = "#FFE0B2";
|
||||
Colors.closed_light = "#FFCCBC";
|
||||
Colors.no_status_light = "#CFD8DC";
|
||||
|
||||
Colors.highlight_conflict = "#F44336";
|
||||
Colors.highlight_default = "#333333";
|
||||
Colors.highlight_saved = "#4CAF50";
|
||||
|
||||
Colors.badge_flash = "#FF5722";
|
||||
Colors.badge_default = "#bf5700";
|
||||
|
||||
class Export {}
|
||||
Export.png_options = {
|
||||
foreignObjectRendering: true,
|
||||
logging: true,
|
||||
removeContainer: true,
|
||||
async: true,
|
||||
};
|
||||
|
||||
class Popup {}
|
||||
Popup.num_semesters = 2;
|
||||
|
||||
class Text {}
|
||||
Text.emptyText = function () {
|
||||
let arr = [
|
||||
"Doesn't Look Like Anything To Me.",
|
||||
"You Can't Fail Classes You're Not In.",
|
||||
"Pro-Tip: Don't Take O-Chem.",
|
||||
"Jendy's Fofofo™",
|
||||
"Fine Dining at Jester City Limits",
|
||||
"Rec Sports is full and it's only 2pm.",
|
||||
"Hope Domino is doing well rn 🥺",
|
||||
"The year is 2055 and Welch still isn't finished.",
|
||||
"Wear a Mask.",
|
||||
"Motivation dropping faster than ur GPA",
|
||||
"No Work Happens On PCL 5th Floor.",
|
||||
"Sophomore But Freshman By Credit.",
|
||||
"Pain is temporary, GPA is forever.",
|
||||
"You've Yee'd Your Last Haw.",
|
||||
"lol everything is already waitlisted.",
|
||||
"At Least You're Not At A&M.",
|
||||
`It's ${moment().format("h:mm")} and OU Still Sucks.`,
|
||||
"TeXAs iS BaCK GuYZ",
|
||||
"'Academically Challenged'",
|
||||
"Does McCombs teach Parseltongue?",
|
||||
"Feel bad if you say Wampus.",
|
||||
"No Cruce Enfrente Del Bus.",
|
||||
"Midterm 1 has been Unmuted",
|
||||
"Omae Wa Mou Shindeiru...",
|
||||
"Bevo Bucks are the new Bitcoin",
|
||||
];
|
||||
let index = Math.floor(Math.random() * arr.length);
|
||||
|
||||
return arr[index];
|
||||
};
|
||||
Text.button_text_default = "<span style='font-size:small'>Import to </span><b>UT Reg +<b>";
|
||||
Text.waitlist_button_text_default = "<span style='font-size:small'>Import Waitlists to </span><b>UT Reg +<b>";
|
||||
Text.button_success = "Courses Saved!";
|
||||
@@ -1,627 +0,0 @@
|
||||
console.log(`UT Registration Plus is running on this page: ${window.location.href}`);
|
||||
|
||||
var curr_course = {}
|
||||
|
||||
var semester_code = new URL(window.location.href).pathname.split('/')[4];
|
||||
var done_loading = true;
|
||||
|
||||
var next = $("#next_nav_link");
|
||||
if (next) {
|
||||
chrome.runtime.sendMessage({
|
||||
command: "getOptionsValue",
|
||||
key: "loadAll",
|
||||
}, function (response) {
|
||||
if(response.value){
|
||||
$('[title*="next listing"]').remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//This extension may be super lit, but you know what's even more lit?
|
||||
//Matthew Tran's twitter and insta: @MATTHEWTRANN and @matthew.trann
|
||||
|
||||
if (document.querySelector('#fos_fl')) {
|
||||
let params = (new URL(document.location)).searchParams;
|
||||
let dep = params.get("fos_fl");
|
||||
let level = params.get("level");
|
||||
if (dep && level) {
|
||||
if (dep.length == 3 && (level == 'U' || level == 'L' || level == 'G')) {
|
||||
document.querySelector('#fos_fl').value = dep;
|
||||
document.querySelector('#level').value = level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//make heading and modal
|
||||
if (!$("#kw_results_table").length) {
|
||||
$("table").after(Template.Catalog.loading());
|
||||
$("#container").prepend(Template.Main.modal());
|
||||
$("#myModal").prepend("<div id='snackbar'>save course popup...</div>");
|
||||
|
||||
// now add to the table
|
||||
$("table thead th:last-child").after('<th scope=col>Plus</th>');
|
||||
$('table').find('tr').each(function () {
|
||||
if (!($(this).find('td').hasClass("course_header")) && $(this).has('th').length == 0) {
|
||||
$(this).append(Template.Main.extension_button());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(isIndividualCoursePage()){
|
||||
chrome.runtime.sendMessage({
|
||||
command: "shouldOpen",
|
||||
}, function (response) {
|
||||
if(response.open){
|
||||
$("#distButton").click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateListConflictHighlighting();
|
||||
|
||||
$("body").on('click', '#distButton', function () {
|
||||
var row = $(this).closest('tr');
|
||||
$('.modal-content').stop().animate({
|
||||
scrollTop: 0
|
||||
}, 500);
|
||||
$(this).blur();
|
||||
curr_course = getCourseInfo(row);
|
||||
getDistribution(curr_course);
|
||||
});
|
||||
|
||||
|
||||
function updateLinks(course_info, first_name) {
|
||||
let {
|
||||
prof_name,
|
||||
number
|
||||
} = course_info;
|
||||
course_info["first_name"] = first_name;
|
||||
course_info["links"]["rate_my_prof"] = `http://www.ratemyprofessors.com/search.jsp?queryBy=teacherName&schoolName=university+of+texas+at+austin&queryoption=HEADER&query=${first_name} ${prof_name};&facetSearch=true`;
|
||||
course_info["links"]["ecis"] = profname ? `http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?&s_in_action_sw=S&s_in_search_type_sw=N&s_in_search_name=${prof_name}%2C%20${first_name}` :
|
||||
`http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?s_in_action_sw=S&s_in_search_type_sw=C&s_in_max_nbr_return=10&s_in_search_course_dept=${department}&s_in_search_course_num=${number}`;
|
||||
}
|
||||
|
||||
|
||||
function buildCourseLinks(course_info) {
|
||||
let {
|
||||
department,
|
||||
number,
|
||||
unique,
|
||||
prof_name
|
||||
} = course_info
|
||||
links = {
|
||||
"textbook": `https://www.universitycoop.com/adoption-search-results?sn=${semester_code}__${department}__${number}__${unique}`,
|
||||
"syllabi": `https://utdirect.utexas.edu/apps/student/coursedocs/nlogon/?year=&semester=&department=${department}&course_number=${number}&course_title=&unique=&instructor_first=&instructor_last=${prof_name}&course_type=In+Residence&search=Search`,
|
||||
//default ones (before first name can be used)
|
||||
"rate_my_prof": "http://www.ratemyprofessors.com/campusRatings.jsp?sid=1255",
|
||||
"ecis": "http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?"
|
||||
}
|
||||
course_info["links"] = links;
|
||||
return course_info;
|
||||
}
|
||||
|
||||
function buildBasicCourseInfo(row, course_name, individual) {
|
||||
let {
|
||||
name,
|
||||
department,
|
||||
number
|
||||
} = separateCourseNameParts(course_name);
|
||||
let instructor_text = $(row).find('td[data-th="Instructor"]').text();
|
||||
let has_initial = instructor_text.indexOf(',') > 0;
|
||||
course_info = {
|
||||
"full_name": course_name,
|
||||
"name": name,
|
||||
"department": department,
|
||||
"number": number,
|
||||
"individual": individual ? individual : $(row).find('td[data-th="Unique"] a').prop('href'),
|
||||
"register": $(row).find('td[data-th="Add"] a').prop('href'),
|
||||
"unique": $(row).find('td[data-th="Unique"]').text(),
|
||||
"status": $(row).find('td[data-th="Status"]').text(),
|
||||
"prof_name": instructor_text ? has_initial ? capitalizeString(instructor_text.split(', ')[0]) : capitalizeString(instructor_text) : "Undecided",
|
||||
"initial": instructor_text && has_initial ? instructor_text.split(', ')[1].substring(0, 1) : "",
|
||||
"time_data": {
|
||||
"days": $(row).find('td[data-th="Days"]>span').toArray().map(x => $(x).text().trim()),
|
||||
"times": $(row).find('td[data-th="Hour"]>span').toArray().map(x => $(x).text().trim()),
|
||||
"places": $(row).find('td[data-th="Room"]>span').toArray().map(x => $(x).text().trim())
|
||||
},
|
||||
"links": {}
|
||||
}
|
||||
return buildCourseLinks(course_info);
|
||||
}
|
||||
|
||||
/*For a row, get all the course information and add the date-time-lines*/
|
||||
function getCourseInfo(row) {
|
||||
let course_name = "";
|
||||
let course_row = {}
|
||||
let individual = undefined;
|
||||
if (isIndividualCoursePage()) {
|
||||
course_name = $("#details h2").text();
|
||||
course_row = $('table');
|
||||
individual = document.URL;
|
||||
} else {
|
||||
$('table').find('tr').each(function () {
|
||||
if ($(this).find('td').hasClass("course_header")) {
|
||||
course_name = $(this).find('td').text() + "";
|
||||
}
|
||||
if ($(this).is(row)) {
|
||||
course_row = row;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
curr_course = buildBasicCourseInfo(course_row, course_name, individual);
|
||||
getDescription(curr_course);
|
||||
return curr_course;
|
||||
}
|
||||
|
||||
function saveCourse() {
|
||||
console.log(curr_course);
|
||||
console.log(JSON.stringify(curr_course));
|
||||
let {
|
||||
full_name,
|
||||
unique,
|
||||
prof_name,
|
||||
status,
|
||||
individual,
|
||||
register
|
||||
} = curr_course;
|
||||
let dtarr = getDayTimeArray(undefined, curr_course);
|
||||
|
||||
var c = new Course(full_name, unique, prof_name, dtarr, status, individual, register);
|
||||
chrome.runtime.sendMessage({
|
||||
command: "courseStorage",
|
||||
course: c,
|
||||
action: $("#saveCourse").val()
|
||||
}, function (response) {
|
||||
$("#saveCourse").text(response.label);
|
||||
$("#saveCourse").val(response.value);
|
||||
$("#snackbar").text(response.done);
|
||||
toggleSnackbar();
|
||||
chrome.runtime.sendMessage({
|
||||
command: "updateCourseList"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* Update the course list to show if the row contains a course that conflicts with the saved course is one of the saved courses */
|
||||
function updateListConflictHighlighting(start = 0) {
|
||||
chrome.runtime.sendMessage({
|
||||
command: "getOptionsValue",
|
||||
key: "courseConflictHighlight",
|
||||
}, function (response) {
|
||||
let canHighlight = response.value;
|
||||
$('table').find('tr').each(function (i) {
|
||||
if (i >= start) {
|
||||
if (!($(this).find('td').hasClass("course_header")) && $(this).has('th').length == 0) {
|
||||
var unique = $(this).find('td[data-th="Unique"]').text();
|
||||
chrome.runtime.sendMessage({
|
||||
command: "isSingleConflict",
|
||||
dtarr: getDayTimeArray(this),
|
||||
unique: unique
|
||||
}, (response) => {
|
||||
let {
|
||||
isConflict,
|
||||
alreadyContains,
|
||||
conflictList
|
||||
} = response
|
||||
updateTextHighlighting($(this).find('td'), canHighlight, isConflict, alreadyContains, conflictList, $(this), unique);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function updateTextHighlighting(tds, canHighlight, isConflict, alreadyContains, conflictList, row, unique) {
|
||||
conflict_texts = row.find('.tooltiptext');
|
||||
let unique_list = conflictList.filter(function(course){
|
||||
if(course.unique != unique){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}).map(function(course){
|
||||
let { name, department, number} = separateCourseNameParts(course.coursename);
|
||||
return `${department} ${number} (${course.unique})`;
|
||||
});
|
||||
if(isConflict && unique_list.length){
|
||||
if(conflict_texts){
|
||||
row.find('.tooltiptext').remove();
|
||||
}
|
||||
row.addClass('tooltip');
|
||||
row.append(`<span class='tooltiptext'><span style='text-decoration: underline;'>Conflicts:<br></span> ${unique_list.join('<br>')}</span>`);
|
||||
} else {
|
||||
row.removeClass('tooltip');
|
||||
conflict_texts.remove();
|
||||
}
|
||||
let current_color = rgb2hex(tds.css('color'));
|
||||
if (isConflict && canHighlight && !alreadyContains) {
|
||||
if (current_color != Colors.highlight_conflict){
|
||||
tds.css('color', Colors.highlight_conflict).css('text-decoration', 'line-through').css('font-weight', 'normal')
|
||||
}
|
||||
|
||||
} else if (!alreadyContains) {
|
||||
if (tds.css('color') != Colors.highlight_default)
|
||||
tds.css('color', Colors.highlight_default).css('text-decoration', 'none').css('font-weight', 'normal');
|
||||
}
|
||||
if (alreadyContains) {
|
||||
if (tds.css('color') != Colors.highlight_saved)
|
||||
tds.css('color', Colors.highlight_saved).css('text-decoration', 'none').css('font-weight', 'bold');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* For a row, get the date-time-array for checking conflicts*/
|
||||
function getDayTimeArray(row, course_info) {
|
||||
var day_time_array = []
|
||||
let days = course_info ? course_info["time_data"]["days"] : $(row).find('td[data-th="Days"]>span').toArray().map(x => $(x).text().trim());
|
||||
let times = course_info ? course_info["time_data"]["times"] : $(row).find('td[data-th="Hour"]>span').toArray().map(x => $(x).text().trim());
|
||||
let places = course_info ? course_info["time_data"]["places"] : $(row).find('td[data-th="Room"]>span').toArray().map(x => $(x).text().trim());
|
||||
for (var i = 0; i < days.length; i++) {
|
||||
let date = days[i];
|
||||
let time = times[i];
|
||||
let place = places[i];
|
||||
for (var j = 0; j < date.length; j++) {
|
||||
let letter = date.charAt(j);
|
||||
if (letter == "T" && j < date.length - 1 && date.charAt(j + 1) == "H") {
|
||||
day_time_array.push(["TH", convertTime(time), place]);
|
||||
} else {
|
||||
if (letter != "H")
|
||||
day_time_array.push([letter, convertTime(time), place]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return day_time_array;
|
||||
}
|
||||
|
||||
function convertDateTimeArrToLine(date, time, place) {
|
||||
let arr = separateDays(date)
|
||||
let output = prettifyDaysText(arr)
|
||||
let building = place.substring(0, place.search(/\d/) - 1);
|
||||
building = building ? building : "Undecided Location";
|
||||
return `${output} at ${time.replace(/\./g, '').replace(/\-/g, ' to ')} in <a style='font-size:medium' target='_blank' href='https://maps.utexas.edu/buildings/UTM/${building}'>${building}</>`;
|
||||
}
|
||||
|
||||
function badData(course_data, res) {
|
||||
return typeof res == 'undefined' || course_data["prof_name"] == "Undecided";
|
||||
}
|
||||
|
||||
/*Query the grades database*/
|
||||
function getDistribution(course_data, sem) {
|
||||
toggleChartLoading(true);
|
||||
let query = buildQuery(course_data, sem);
|
||||
chrome.runtime.sendMessage({
|
||||
command: "gradesQuery",
|
||||
query: query
|
||||
}, function (response) {
|
||||
var res = response.data;
|
||||
if (!sem) {
|
||||
openDialog(course_data, res);
|
||||
} else {
|
||||
var data = badData(course_data, res) ? [] : res.values[0];
|
||||
setChart(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildTitle(course_data) {
|
||||
return `${course_data["name"]} (${course_data["department"]} ${course_data["number"]})`
|
||||
}
|
||||
|
||||
function buildTimeTitle(course_info) {
|
||||
$("h2.dateTimePlace").remove();
|
||||
let {
|
||||
days,
|
||||
times,
|
||||
places
|
||||
} = course_info["time_data"]
|
||||
var lines = [];
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
var date = days[i];
|
||||
var time = times[i];
|
||||
var place = places[i];
|
||||
lines.push($(`<h2 class="dateTimePlace">${convertDateTimeArrToLine(date, time, place)}</th>`));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function buildProfTitle(course_data) {
|
||||
const {
|
||||
initial,
|
||||
prof_name
|
||||
} = course_data;
|
||||
return `with ${initial?initial+". ":""}${prof_name}`;
|
||||
}
|
||||
|
||||
|
||||
function buildSemestersDropdown(course_data, res) {
|
||||
$("#semesters").empty();
|
||||
if (badData(course_data, res)) {
|
||||
$("#semesters").append("<option>No Data</option>")
|
||||
} else {
|
||||
var semesters = res.values[0][18].split(",");
|
||||
semesters.sort(semesterSort);
|
||||
semesters.reverse().unshift('Aggregate');
|
||||
var sems = [];
|
||||
for (var i = 0; i < semesters.length; i++) {
|
||||
sems.push($(`<option value="${semesters[i]}">${semesters[i]}</option>`));
|
||||
}
|
||||
$("#semesters").append(sems);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function displayBasicCourseInfo(course_info){
|
||||
$("#title").text(buildTitle(course_info))
|
||||
$("#topbuttons").before(buildTimeTitle(course_info));
|
||||
$("#profname").text(buildProfTitle(course_info));
|
||||
$("#myModal").fadeIn(Timing.fade_time);
|
||||
console.log(course_info);
|
||||
}
|
||||
|
||||
/*Open the modal and show all the data*/
|
||||
function openDialog(course_info, res) {
|
||||
displayBasicCourseInfo(course_info);
|
||||
//initial text on the "save course button"
|
||||
chrome.runtime.sendMessage({
|
||||
command: "alreadyContains",
|
||||
unique: course_info["unique"]
|
||||
}, function (response) {
|
||||
|
||||
let button_text = response.alreadyContains ? "Remove Course -" : "Add Course +";
|
||||
let button_val = response.alreadyContains ? "remove" : "add";
|
||||
$("#saveCourse").text(button_text);
|
||||
$("#saveCourse").val(button_val);
|
||||
});
|
||||
buildSemestersDropdown(course_info, res)
|
||||
var data = []
|
||||
if (!badData(course_info, res))
|
||||
data = res.values[0];
|
||||
allowClosing();
|
||||
setChart(data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function setChart(data) {
|
||||
// set up the chart
|
||||
toggleChartLoading(false);
|
||||
Highcharts.chart('chart', buildChartConfig(data), function (chart) { // on complete
|
||||
if (data.length == 0) {
|
||||
//if no data, then show the message and hide the series
|
||||
chart.renderer.text('Could not find data for this Instructor teaching this Course.', 100, 120)
|
||||
.css({
|
||||
fontSize: '20px',
|
||||
width: '300px',
|
||||
align: 'center',
|
||||
left: '160px'
|
||||
})
|
||||
.add();
|
||||
$.each(chart.series, function (i, ser) {
|
||||
ser.hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var error_message = "<p style='color:red;font-style:bold'>You have been logged out. Please refresh the page and log back in using your UT EID and password.</p>";
|
||||
|
||||
function buildFormattedDescription(description_lines) {
|
||||
let description = ""
|
||||
for (let i in description_lines) {
|
||||
let sentence = description_lines[i];
|
||||
if (sentence.indexOf("Prerequisite") == 0)
|
||||
sentence = `<li style='font-weight: bold;' class='descriptionli'>${sentence}</li>`;
|
||||
else if (sentence.indexOf("May be") >= 0)
|
||||
sentence = `<li style='font-style: italic;' class='descriptionli'>${sentence}</li>`;
|
||||
else if (sentence.indexOf("Restricted to") == 0)
|
||||
sentence = `<li style='color:red;' class='descriptionli'>${sentence}</li>`;
|
||||
else
|
||||
sentence = `<li class='descriptionli'>${sentence}</li>`;
|
||||
description += sentence;
|
||||
}
|
||||
if (!description)
|
||||
description = error_message;
|
||||
return description;
|
||||
}
|
||||
|
||||
function extractFirstName(response_node) {
|
||||
let full_name = response_node.find('td[data-th="Instructor"]').text().split(', ');
|
||||
let first = full_name[full_name.length - 1];
|
||||
first = first.indexOf(' ') > 0 ? first.split(' ')[0] : first;
|
||||
return capitalizeString(first);
|
||||
}
|
||||
|
||||
function displayDescription(description) {
|
||||
toggleDescriptionLoading(false);
|
||||
$("#description").animate({
|
||||
'opacity': 0
|
||||
}, 200, function () {
|
||||
$(this).html(description).animate({
|
||||
'opacity': 1
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
/*Get the course description from the profurl and highlight the important elements, as well as set the eCIS, and rmp links.*/
|
||||
function getDescription(course_info) {
|
||||
toggleDescriptionLoading(true);
|
||||
$.ajax({
|
||||
url: course_info["individual"],
|
||||
success: function (response) {
|
||||
if (response) {
|
||||
let response_node = htmlToNode(response);
|
||||
description_lines = response_node.find('#details > p').toArray().map(x => $(x).text());
|
||||
displayDescription(buildFormattedDescription(description_lines));
|
||||
let first_name = extractFirstName(response_node);
|
||||
updateLinks(course_info, first_name);
|
||||
} else {
|
||||
displayDescription(error_message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadNextPages(num_pages) {
|
||||
if (num_pages === undefined) num_pages = 1;
|
||||
if (num_pages == 0) return;
|
||||
chrome.runtime.sendMessage({
|
||||
command: "getOptionsValue",
|
||||
key: "loadAll",
|
||||
}, function (response) {
|
||||
if(response.value){
|
||||
let link = next.prop('href');
|
||||
if (done_loading && next && link) {
|
||||
toggleLoadingPage(true);
|
||||
$.get(link, function (response) {
|
||||
if (response) {
|
||||
var next_page = htmlToNode(response);
|
||||
var current = $('tbody');
|
||||
var old_length = $('tbody tr').length;
|
||||
var last = current.find('.course_header>h2:last').text();
|
||||
next = next_page.find("#next_nav_link");
|
||||
toggleLoadingPage(false);
|
||||
var new_rows = [];
|
||||
next_page.find('tbody>tr').each(function () {
|
||||
let has_course_header = $(this).find('td').hasClass("course_header");
|
||||
if (!(has_course_header && $(this).has('th').length == 0))
|
||||
$(this).append(Template.Main.extension_button());
|
||||
if (!(has_course_header && last == $(this).find('td').text()))
|
||||
new_rows.push($(this));
|
||||
});
|
||||
current.append(new_rows);
|
||||
updateListConflictHighlighting(old_length + 1)
|
||||
}
|
||||
loadNextPages(num_pages-1);
|
||||
}).fail(function () {
|
||||
toggleLoadingPage(false);
|
||||
$("#retrylabel").css('display', 'inline-block');
|
||||
$('#retry').css('display', 'inline-block');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$("#myModal").on('click', '#saveCourse', function () {
|
||||
setTimeout(function () {
|
||||
saveCourse();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$("#Syllabi").click(function () {
|
||||
setTimeout(function () {
|
||||
window.open(curr_course["links"]["syllabi"]);
|
||||
}, Timing.button_delay);
|
||||
});
|
||||
$("#rateMyProf").click(function () {
|
||||
setTimeout(function () {
|
||||
window.open(curr_course["links"]["rate_my_prof"]);
|
||||
}, Timing.button_delay);
|
||||
});
|
||||
$("#eCIS").click(function () {
|
||||
setTimeout(function () {
|
||||
window.open(curr_course["links"]["ecis"]);
|
||||
}, Timing.button_delay);
|
||||
});
|
||||
$("#textbook").click(function () {
|
||||
setTimeout(function () {
|
||||
window.open(curr_course["links"]["textbook"]);
|
||||
}, Timing.button_delay);
|
||||
});
|
||||
$("#semesters").on('change', function () {
|
||||
let sem = $(this).val();
|
||||
sem = sem == "Aggregate" ? undefined : sem;
|
||||
getDistribution(curr_course, sem);
|
||||
});
|
||||
|
||||
$("#retry").click(function () {
|
||||
$("#retrylabel").hide();
|
||||
$(this).hide();
|
||||
loadNextPages();
|
||||
});
|
||||
|
||||
function toggleLoadingPage(loading) {
|
||||
if (loading) {
|
||||
done_loading = false;
|
||||
$('#loader').css('display', 'inline-block');
|
||||
$("#nextlabel").css('display', 'inline-block');
|
||||
} else {
|
||||
done_loading = true;
|
||||
$('#loader').hide();
|
||||
$("#nextlabel").hide();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleChartLoading(loading) {
|
||||
if (loading) {
|
||||
$('#chartload').css('display', 'inline-block');
|
||||
$("#chart").hide();
|
||||
} else {
|
||||
$('#chartload').hide();
|
||||
$("#chart").show();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleDescriptionLoading(loading) {
|
||||
if (loading) {
|
||||
$('#descload').css('display', 'inline-block');
|
||||
} else {
|
||||
$('#descload').hide();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSnackbar() {
|
||||
setTimeout(function () {
|
||||
$("#snackbar").attr("class", "show");
|
||||
}, 200);
|
||||
setTimeout(function () {
|
||||
$("#snackbar").attr("class", "");
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
|
||||
function allowClosing() {
|
||||
$('.close').click(function () {
|
||||
close();
|
||||
});
|
||||
$('#myModal').click(function (event) {
|
||||
if (event.target.id == 'myModal') {
|
||||
close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
$("#myModal").fadeOut(Timing.fade_time);
|
||||
$("#snackbar").attr("class", "");
|
||||
}
|
||||
|
||||
/*Listen for update mssage coming from popup or calendar or other course catalog pages*/
|
||||
chrome.runtime.onMessage.addListener(
|
||||
function (request, sender, sendResponse) {
|
||||
if (request.command == "updateCourseList") {
|
||||
updateListConflictHighlighting(0);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
$(document).keydown(function (e) {
|
||||
/*Close Modal when hit escape*/
|
||||
if (e.keyCode == 27) {
|
||||
close();
|
||||
} else if (e.keyCode == 13 && $('#myModal').is(':visible')) {
|
||||
saveCourse();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$(window).scroll(function () {
|
||||
if ($(document).height() <= $(window).scrollTop() + $(window).height() + 150)
|
||||
loadNextPages();
|
||||
});
|
||||
|
||||
|
||||
$(window).on('load', function () {
|
||||
loadNextPages(3);
|
||||
});
|
||||
164
js/import.js
@@ -1,164 +0,0 @@
|
||||
var waitlist;
|
||||
var sem;
|
||||
$(function () {
|
||||
waitlist = !(window.location.href.includes('https://utdirect.utexas.edu/registration/classlist.WBX'));
|
||||
sem = waitlist ? $('[name="s_ccyys"]').val() : $("option[selected='selected']").val();
|
||||
if (waitlist) {
|
||||
$("[href='#top']").before(Template.Import.import_button());
|
||||
$("[name='wl_see_my_waitlists']").before(Template.Import.store_waitlist_message());
|
||||
$("[name='wl_see_my_waitlists']").after(Template.Import.waitlist_import_button());
|
||||
extractWaitlistInfo();
|
||||
} else {
|
||||
$("table").after(Template.Import.import_button());
|
||||
}
|
||||
$("#import").prepend("<div id='snackbar'>import snackbar..</div>");
|
||||
|
||||
$("#import").click(function () {
|
||||
search_nodes = waitlist ? $(".tbg").last().find(".tbon>td:first-child") : $("tr>td:first-child");
|
||||
$(search_nodes).each(function () {
|
||||
importCourse($(this), true);
|
||||
})
|
||||
importButtonAnimation($(this));
|
||||
});
|
||||
|
||||
$("#import_waitlist").click(function () {
|
||||
search_nodes = $("tr.tb span:first-child");
|
||||
$(search_nodes).each(function () {
|
||||
importCourse($(this), false);
|
||||
})
|
||||
importButtonAnimation($(this));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function extractWaitlistInfo(){
|
||||
let class_boxes = $("[name='wl_see_my_waitlists']>table");
|
||||
let waitlist_info = [];
|
||||
$(class_boxes).each(function(){
|
||||
let data = $(this).find('tr.tb span');
|
||||
let unique_num = $(data[0]).text().trim();
|
||||
let class_name = $(data[1]).text().trim().split('\n').filter(part => part.trim() != '').map(part => part.trim()).join(' ');
|
||||
let waitlist_size = $(this).find('tr.tbon:eq(2) td:eq(1)').text().trim().split(' of ')[1];
|
||||
|
||||
waitlist_info.push({
|
||||
"id": unique_num,
|
||||
"class": class_name,
|
||||
"wait": waitlist_size,
|
||||
"time": moment().format('DD-MM-YYYY HH:mm:ss')
|
||||
});
|
||||
});
|
||||
console.log(waitlist_info);
|
||||
return waitlist_info;
|
||||
}
|
||||
|
||||
|
||||
function importButtonAnimation(button) {
|
||||
let is_waitlisted_button = $(button).attr('id') == "import_waitlist";
|
||||
let return_text = is_waitlisted_button ? Text.waitlist_button_text_default : Text.button_text_default;
|
||||
$(button).text(Text.button_success).css("background-color", Colors.open);
|
||||
setTimeout(function () {
|
||||
$(button).html(return_text).css('background-color', Colors.waitlisted);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function importCourse(unique_node, force) {
|
||||
let unique = $(unique_node).text().replace(/\s/g, '').substring(0,5);
|
||||
link = `https://utdirect.utexas.edu/apps/registrar/course_schedule/${sem}/${unique}/`;
|
||||
buildAddCourse(link, force)
|
||||
}
|
||||
|
||||
|
||||
function buildAddCourse(link, force) {
|
||||
$.get(link, function (response) {
|
||||
if (response) {
|
||||
let simp_course = buildSimplifiedCourseObject(response, link, force);
|
||||
chrome.runtime.sendMessage({
|
||||
command: "courseStorage",
|
||||
course: simp_course,
|
||||
action: "add"
|
||||
}, function () {
|
||||
chrome.runtime.sendMessage({
|
||||
command: "updateCourseList"
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function buildSimplifiedCourseObject(response, link, force) {
|
||||
let imported_course = getCourseObject(htmlToNode(response), link);
|
||||
let {
|
||||
full_name,
|
||||
unique,
|
||||
prof_name,
|
||||
individual,
|
||||
status,
|
||||
register
|
||||
} = curr_course;
|
||||
let dtarr = getDayTimeArray(undefined, curr_course);
|
||||
if(force === true) {
|
||||
status = "open" //forces the green status for courses a user is already registered for
|
||||
}
|
||||
return new Course(full_name, unique, prof_name, dtarr, status, individual, register);
|
||||
}
|
||||
|
||||
/*For a row, get all the course information and add the date-time-lines*/
|
||||
function getCourseObject(response_node, individual) {
|
||||
let course_name = $(response_node).find("#details h2").text();
|
||||
let course_row = $(response_node).find('table');
|
||||
curr_course = buildBasicCourseInfo(course_row, course_name, individual);
|
||||
}
|
||||
|
||||
|
||||
function buildBasicCourseInfo(row, course_name, individual) {
|
||||
let {
|
||||
name,
|
||||
department,
|
||||
number
|
||||
} = separateCourseNameParts(course_name);
|
||||
let instructor_text = $(row).find('td[data-th="Instructor"]').text();
|
||||
let has_initial = instructor_text.indexOf(',') > 0;
|
||||
course_info = {
|
||||
"full_name": course_name,
|
||||
"name": name,
|
||||
"department": department,
|
||||
"number": number,
|
||||
"individual": individual ? individual : $(row).find('td[data-th="Unique"] a').prop('href'),
|
||||
"register": $(row).find('td[data-th="Add"] a').prop('href'),
|
||||
"unique": $(row).find('td[data-th="Unique"]').text(),
|
||||
"status": $(row).find('td[data-th="Status"]').text(),
|
||||
"prof_name": instructor_text ? has_initial ? capitalizeString(instructor_text.split(', ')[0]) : capitalizeString(instructor_text) : "Undecided",
|
||||
"initial": instructor_text && has_initial ? instructor_text.split(', ')[1].substring(0, 1) : "",
|
||||
"time_data": {
|
||||
"days": $(row).find('td[data-th="Days"]>span').toArray().map(x => $(x).text().trim()),
|
||||
"times": $(row).find('td[data-th="Hour"]>span').toArray().map(x => $(x).text().trim()),
|
||||
"places": $(row).find('td[data-th="Room"]>span').toArray().map(x => $(x).text().trim())
|
||||
},
|
||||
"links": {}
|
||||
}
|
||||
return course_info;
|
||||
}
|
||||
|
||||
/* For a row, get the date-time-array for checking conflicts*/
|
||||
function getDayTimeArray(row, course_info) {
|
||||
var day_time_array = []
|
||||
let days = course_info ? course_info["time_data"]["days"] : $(row).find('td[data-th="Days"]>span').toArray().map(x => $(x).text().trim());
|
||||
let times = course_info ? course_info["time_data"]["times"] : $(row).find('td[data-th="Hour"]>span').toArray().map(x => $(x).text().trim());
|
||||
let places = course_info ? course_info["time_data"]["places"] : $(row).find('td[data-th="Room"]>span').toArray().map(x => $(x).text().trim());
|
||||
for (var i = 0; i < days.length; i++) {
|
||||
let date = days[i];
|
||||
let time = times[i];
|
||||
let place = places[i];
|
||||
for (var j = 0; j < date.length; j++) {
|
||||
let letter = date.charAt(j);
|
||||
if (letter == "T" && j < date.length - 1 && date.charAt(j + 1) == "H") {
|
||||
day_time_array.push(["TH", convertTime(time), place]);
|
||||
} else {
|
||||
if (letter != "H")
|
||||
day_time_array.push([letter, convertTime(time), place]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return day_time_array;
|
||||
}
|
||||
1
js/lib/fullcalendar.min.js
vendored
8737
js/lib/highcharts.js
6
js/lib/html2canvas.min.js
vendored
231
js/lib/ics.min.js
vendored
@@ -1,231 +0,0 @@
|
||||
/*! ics.js Wed Aug 20 2014 17:23:02 */
|
||||
var saveAs = saveAs || function (e) {
|
||||
"use strict";
|
||||
if (typeof e === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
|
||||
return
|
||||
}
|
||||
var t = e.document,
|
||||
n = function () {
|
||||
return e.URL || e.webkitURL || e
|
||||
},
|
||||
r = t.createElementNS("http://www.w3.org/1999/xhtml", "a"),
|
||||
o = "download" in r,
|
||||
a = function (e) {
|
||||
var t = new MouseEvent("click");
|
||||
e.dispatchEvent(t)
|
||||
},
|
||||
i = /constructor/i.test(e.HTMLElement) || e.safari,
|
||||
f = /CriOS\/[\d]+/.test(navigator.userAgent),
|
||||
u = function (t) {
|
||||
(e.setImmediate || e.setTimeout)(function () {
|
||||
throw t
|
||||
}, 0)
|
||||
},
|
||||
s = "application/octet-stream",
|
||||
d = 1e3 * 40,
|
||||
c = function (e) {
|
||||
var t = function () {
|
||||
if (typeof e === "string") {
|
||||
n().revokeObjectURL(e)
|
||||
} else {
|
||||
e.remove()
|
||||
}
|
||||
};
|
||||
setTimeout(t, d)
|
||||
},
|
||||
l = function (e, t, n) {
|
||||
t = [].concat(t);
|
||||
var r = t.length;
|
||||
while (r--) {
|
||||
var o = e["on" + t[r]];
|
||||
if (typeof o === "function") {
|
||||
try {
|
||||
o.call(e, n || e)
|
||||
} catch (a) {
|
||||
u(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
p = function (e) {
|
||||
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)) {
|
||||
return new Blob([String.fromCharCode(65279), e], {
|
||||
type: e.type
|
||||
})
|
||||
}
|
||||
return e
|
||||
},
|
||||
v = function (t, u, d) {
|
||||
if (!d) {
|
||||
t = p(t)
|
||||
}
|
||||
var v = this,
|
||||
w = t.type,
|
||||
m = w === s,
|
||||
y, h = function () {
|
||||
l(v, "writestart progress write writeend".split(" "))
|
||||
},
|
||||
S = function () {
|
||||
if ((f || m && i) && e.FileReader) {
|
||||
var r = new FileReader;
|
||||
r.onloadend = function () {
|
||||
var t = f ? r.result : r.result.replace(/^data:[^;]*;/, "data:attachment/file;");
|
||||
var n = e.open(t, "_blank");
|
||||
if (!n) e.location.href = t;
|
||||
t = undefined;
|
||||
v.readyState = v.DONE;
|
||||
h()
|
||||
};
|
||||
r.readAsDataURL(t);
|
||||
v.readyState = v.INIT;
|
||||
return
|
||||
}
|
||||
if (!y) {
|
||||
y = n().createObjectURL(t)
|
||||
}
|
||||
if (m) {
|
||||
e.location.href = y
|
||||
} else {
|
||||
var o = e.open(y, "_blank");
|
||||
if (!o) {
|
||||
e.location.href = y
|
||||
}
|
||||
}
|
||||
v.readyState = v.DONE;
|
||||
h();
|
||||
c(y)
|
||||
};
|
||||
v.readyState = v.INIT;
|
||||
if (o) {
|
||||
y = n().createObjectURL(t);
|
||||
setTimeout(function () {
|
||||
r.href = y;
|
||||
r.download = u;
|
||||
a(r);
|
||||
h();
|
||||
c(y);
|
||||
v.readyState = v.DONE
|
||||
});
|
||||
return
|
||||
}
|
||||
S()
|
||||
},
|
||||
w = v.prototype,
|
||||
m = function (e, t, n) {
|
||||
return new v(e, t || e.name || "download", n)
|
||||
};
|
||||
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
|
||||
return function (e, t, n) {
|
||||
t = t || e.name || "download";
|
||||
if (!n) {
|
||||
e = p(e)
|
||||
}
|
||||
return navigator.msSaveOrOpenBlob(e, t)
|
||||
}
|
||||
}
|
||||
w.abort = function () {};
|
||||
w.readyState = w.INIT = 0;
|
||||
w.WRITING = 1;
|
||||
w.DONE = 2;
|
||||
w.error = w.onwritestart = w.onprogress = w.onwrite = w.onabort = w.onerror = w.onwriteend = null;
|
||||
return m
|
||||
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content);
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
module.exports.saveAs = saveAs
|
||||
} else if (typeof define !== "undefined" && define !== null && define.amd !== null) {
|
||||
define("FileSaver.js", function () {
|
||||
return saveAs
|
||||
})
|
||||
}
|
||||
|
||||
var ics = function (e, t) {
|
||||
"use strict"; {
|
||||
if (!(navigator.userAgent.indexOf("MSIE") > -1 && -1 == navigator.userAgent.indexOf("MSIE 10"))) {
|
||||
void 0 === e && (e = "default"), void 0 === t && (t = "Calendar");
|
||||
var r = -1 !== navigator.appVersion.indexOf("Win") ? "\r\n" : "\n",
|
||||
n = [],
|
||||
i = ["BEGIN:VCALENDAR", "PRODID:" + t, "VERSION:2.0"].join(r),
|
||||
o = r + "END:VCALENDAR",
|
||||
a = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
|
||||
return {
|
||||
events: function () {
|
||||
return n
|
||||
},
|
||||
calendar: function () {
|
||||
return i + r + n.join(r) + o
|
||||
},
|
||||
addEvent: function (t, i, o, l, u, s) {
|
||||
if (void 0 === t || void 0 === i || void 0 === o || void 0 === l || void 0 === u) return !1;
|
||||
if (s && !s.rrule) {
|
||||
if ("YEARLY" !== s.freq && "MONTHLY" !== s.freq && "WEEKLY" !== s.freq && "DAILY" !== s.freq) throw "Recurrence rrule frequency must be provided and be one of the following: 'YEARLY', 'MONTHLY', 'WEEKLY', or 'DAILY'";
|
||||
if (s.until && isNaN(Date.parse(s.until))) throw "Recurrence rrule 'until' must be a valid date string";
|
||||
if (s.interval && isNaN(parseInt(s.interval))) throw "Recurrence rrule 'interval' must be an integer";
|
||||
if (s.count && isNaN(parseInt(s.count))) throw "Recurrence rrule 'count' must be an integer";
|
||||
if (void 0 !== s.byday) {
|
||||
if ("[object Array]" !== Object.prototype.toString.call(s.byday)) throw "Recurrence rrule 'byday' must be an array";
|
||||
if (s.byday.length > 7) throw "Recurrence rrule 'byday' array must not be longer than the 7 days in a week";
|
||||
s.byday = s.byday.filter(function (e, t) {
|
||||
return s.byday.indexOf(e) == t
|
||||
});
|
||||
for (var c in s.byday)
|
||||
if (a.indexOf(s.byday[c]) < 0) throw "Recurrence rrule 'byday' values must include only the following: 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'"
|
||||
}
|
||||
}
|
||||
var g = new Date(l),
|
||||
d = new Date(u),
|
||||
f = new Date,
|
||||
S = ("0000" + g.getFullYear().toString()).slice(-4),
|
||||
E = ("00" + (g.getMonth() + 1).toString()).slice(-2),
|
||||
v = ("00" + g.getDate().toString()).slice(-2),
|
||||
y = ("00" + g.getHours().toString()).slice(-2),
|
||||
A = ("00" + g.getMinutes().toString()).slice(-2),
|
||||
T = ("00" + g.getSeconds().toString()).slice(-2),
|
||||
b = ("0000" + d.getFullYear().toString()).slice(-4),
|
||||
D = ("00" + (d.getMonth() + 1).toString()).slice(-2),
|
||||
N = ("00" + d.getDate().toString()).slice(-2),
|
||||
h = ("00" + d.getHours().toString()).slice(-2),
|
||||
I = ("00" + d.getMinutes().toString()).slice(-2),
|
||||
R = ("00" + d.getMinutes().toString()).slice(-2),
|
||||
M = ("0000" + f.getFullYear().toString()).slice(-4),
|
||||
w = ("00" + (f.getMonth() + 1).toString()).slice(-2),
|
||||
L = ("00" + f.getDate().toString()).slice(-2),
|
||||
O = ("00" + f.getHours().toString()).slice(-2),
|
||||
p = ("00" + f.getMinutes().toString()).slice(-2),
|
||||
Y = ("00" + f.getMinutes().toString()).slice(-2),
|
||||
U = "",
|
||||
V = "";
|
||||
y + A + T + h + I + R != 0 && (U = "T" + y + A + T, V = "T" + h + I + R);
|
||||
var B, C = S + E + v + U,
|
||||
j = b + D + N + V,
|
||||
m = M + w + L + ("T" + O + p + Y);
|
||||
if (s)
|
||||
if (s.rrule) B = s.rrule;
|
||||
else {
|
||||
if (B = "rrule:FREQ=" + s.freq, s.until) {
|
||||
var x = new Date(Date.parse(s.until)).toISOString();
|
||||
B += ";UNTIL=" + x.substring(0, x.length - 13).replace(/[-]/g, "") + "000000Z"
|
||||
}
|
||||
s.interval && (B += ";INTERVAL=" + s.interval), s.count && (B += ";COUNT=" + s.count), s.byday && s.byday.length > 0 && (B += ";BYDAY=" + s.byday.join(","))
|
||||
}(new Date).toISOString();
|
||||
var H = ["BEGIN:VEVENT", "UID:" + n.length + "@" + e, "CLASS:PUBLIC", "DESCRIPTION:" + i, "DTSTAMP;VALUE=DATE-TIME:" + m, "DTSTART;VALUE=DATE-TIME:" + C, "DTEND;VALUE=DATE-TIME:" + j, "LOCATION:" + o, "SUMMARY;LANGUAGE=en-us:" + t, "TRANSP:TRANSPARENT", "END:VEVENT"];
|
||||
return B && H.splice(4, 0, B), H = H.join(r), n.push(H), H
|
||||
},
|
||||
download: function (e, t) {
|
||||
if (n.length < 1) return !1;
|
||||
t = void 0 !== t ? t : ".ics", e = void 0 !== e ? e : "calendar";
|
||||
var a, l = i + r + n.join(r) + o;
|
||||
if (-1 === navigator.userAgent.indexOf("MSIE 10")) a = new Blob([l]);
|
||||
else {
|
||||
var u = new BlobBuilder;
|
||||
u.append(l), a = u.getBlob("text/x-vCalendar;charset=" + document.characterSet)
|
||||
}
|
||||
return saveAs(a, e + t), l
|
||||
},
|
||||
build: function () {
|
||||
return !(n.length < 1) && i + r + n.join(r) + o
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log("Unsupported Browser")
|
||||
}
|
||||
};
|
||||
2
js/lib/jquery-3.3.1.min.js
vendored
1
js/lib/jquery.initialize.min.js
vendored
@@ -1 +0,0 @@
|
||||
(function($){"use strict";var combinators=[" ",">","+","~"];var fraternisers=["+","~"];var complexTypes=["ATTR","PSEUDO","ID","CLASS"];function grok(msobserver){if(!$.find.tokenize){msobserver.isCombinatorial=true;msobserver.isFraternal=true;msobserver.isComplex=true;return}msobserver.isCombinatorial=false;msobserver.isFraternal=false;msobserver.isComplex=false;var token=$.find.tokenize(msobserver.selector);for(var i=0;i<token.length;i++){for(var j=0;j<token[i].length;j++){if(combinators.indexOf(token[i][j].type)!=-1)msobserver.isCombinatorial=true;if(fraternisers.indexOf(token[i][j].type)!=-1)msobserver.isFraternal=true;if(complexTypes.indexOf(token[i][j].type)!=-1)msobserver.isComplex=true}}}var MutationSelectorObserver=function(selector,callback,options){this.selector=selector.trim();this.callback=callback;this.options=options;grok(this)};var msobservers=[];msobservers.initialize=function(selector,callback,options){var seen=[];var callbackOnce=function(){if(seen.indexOf(this)==-1){seen.push(this);$(this).each(callback)}};$(options.target).find(selector).each(callbackOnce);var msobserver=new MutationSelectorObserver(selector,callbackOnce,options);this.push(msobserver);var observer=new MutationObserver(function(mutations){var matches=[];for(var m=0;m<mutations.length;m++){if(mutations[m].type=="attributes"){if(mutations[m].target.matches(msobserver.selector))matches.push(mutations[m].target);if(msobserver.isFraternal)matches.push.apply(matches,mutations[m].target.parentElement.querySelectorAll(msobserver.selector));else matches.push.apply(matches,mutations[m].target.querySelectorAll(msobserver.selector))}if(mutations[m].type=="childList"){for(var n=0;n<mutations[m].addedNodes.length;n++){if(!(mutations[m].addedNodes[n]instanceof Element))continue;if(mutations[m].addedNodes[n].matches(msobserver.selector))matches.push(mutations[m].addedNodes[n]);if(msobserver.isFraternal)matches.push.apply(matches,mutations[m].addedNodes[n].parentElement.querySelectorAll(msobserver.selector));else matches.push.apply(matches,mutations[m].addedNodes[n].querySelectorAll(msobserver.selector))}}}for(var i=0;i<matches.length;i++)$(matches[i]).each(msobserver.callback)});var defaultObeserverOpts={childList:true,subtree:true,attributes:msobserver.isComplex};observer.observe(options.target,options.observer||defaultObeserverOpts);return observer};$.fn.initialize=function(callback,options){return msobservers.initialize(this.selector,callback,$.extend({},$.initialize.defaults,options))};$.initialize=function(selector,callback,options){return msobservers.initialize(selector,callback,$.extend({},$.initialize.defaults,options))};$.initialize.defaults={target:document.documentElement,observer:null}})(jQuery);
|
||||
1
js/lib/moment.min.js
vendored
@@ -1,60 +0,0 @@
|
||||
var manifestData = chrome.runtime.getManifest();
|
||||
$("#version").text(manifestData.version);
|
||||
|
||||
chrome.storage.sync.get("options", function (data) {
|
||||
if (data.options) {
|
||||
console.log(data.options);
|
||||
Object.keys(data.options).forEach(key => {
|
||||
let enabled = data.options[key];
|
||||
$("#options_container").append(Template.Options.options_row(key, enabled));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("body").on("click", "button", function () {
|
||||
let key = $(this).attr("id");
|
||||
let old_status = $(this).val() === "true";
|
||||
let new_status = !old_status;
|
||||
chrome.runtime.sendMessage(
|
||||
{
|
||||
command: "setOptionsValue",
|
||||
key: key,
|
||||
value: new_status,
|
||||
},
|
||||
function (response) {
|
||||
console.log(response.value);
|
||||
toggle(key, response.value);
|
||||
updateAllTabsCourseList();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$.get("https://api.github.com/repos/sghsri/UT-Registration-Plus/stats/contributors", data => {
|
||||
data = data.sort((a, b) => b.total - a.total);
|
||||
console.log("data", data);
|
||||
for (var contributorData of data) {
|
||||
$.get(`https://api.github.com/users/${contributorData.author.login}`, userData => {
|
||||
let fullData = { ...contributorData, ...userData };
|
||||
let { login, avatar_url, html_url, name } = fullData;
|
||||
if(name){
|
||||
$("#contributor-list").append(Template.Options.contributor_card(login, name, avatar_url, html_url));
|
||||
}
|
||||
else{
|
||||
$("#contributor-list").append(Template.Options.contributor_card("", login, avatar_url, html_url));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("body").on("click", ".contributor-card", function () {
|
||||
console.log("hello world");
|
||||
window.open($(this).data("url"), "_blank");
|
||||
});
|
||||
|
||||
function toggle(key, value) {
|
||||
let button_text = value ? "Turn Off" : "Turn On";
|
||||
let button_color = value ? Colors.closed : Colors.open;
|
||||
$(`#${key}`).text(button_text);
|
||||
$(`#${key}`).css("background", button_color);
|
||||
$(`#${key}`).val(value);
|
||||
}
|
||||
437
js/popup.js
@@ -1,437 +0,0 @@
|
||||
var courses;
|
||||
|
||||
setCourseList();
|
||||
getSemesters();
|
||||
getDepartments();
|
||||
|
||||
var can_remove = true;
|
||||
|
||||
function setCourseList() {
|
||||
$("#courseList").empty();
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
updateConflicts();
|
||||
courses = data.savedCourses;
|
||||
handleEmpty();
|
||||
let hours = 0;
|
||||
// build and append the course list element
|
||||
for (var i = 0; i < courses.length; i++) {
|
||||
let { coursename, unique, profname, status, datetimearr } = courses[i];
|
||||
profname = capitalizeString(profname);
|
||||
let line = buildTimeLines(datetimearr);
|
||||
let list_tile_color = getStatusColor(status);
|
||||
let list_sub_color = getStatusColor(status, true);
|
||||
let { department, number } = separateCourseNameParts(coursename);
|
||||
let class_length = parseInt(number.charAt(0));
|
||||
let multi_semester_code = number.slice(-1);
|
||||
if (["A", "B"].includes(multi_semester_code)) {
|
||||
hours += Math.floor(class_length / 2);
|
||||
} else if (["X", "Y", "Z"].includes(multi_semester_code)) {
|
||||
hours += Math.floor(class_length / 3);
|
||||
} else {
|
||||
hours += class_length;
|
||||
}
|
||||
let list_html = Template.Popup.list_item(i, list_tile_color, unique, department, number, profname, list_sub_color, line);
|
||||
$("#courseList").append(list_html);
|
||||
}
|
||||
$("#meta-metric").text(hours);
|
||||
});
|
||||
}
|
||||
|
||||
/* convert from the dtarr and maek the time lines*/
|
||||
function buildTimeLines(datetimearr) {
|
||||
let lines = convertDateTimeArrToLine(datetimearr);
|
||||
let output = "";
|
||||
if (lines.length == 0) {
|
||||
output = "<span style='font-size:medium;'>This class has no meeting times.</span>";
|
||||
} else {
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let line = lines[i];
|
||||
output += Template.Popup.line(line);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/* Update the conflict messages */
|
||||
function updateConflicts() {
|
||||
chrome.runtime.sendMessage(
|
||||
{
|
||||
command: "checkConflicts",
|
||||
},
|
||||
function (response) {
|
||||
console.log("updateConflicts -> response", response);
|
||||
if (response.isConflict) {
|
||||
var between = response.between;
|
||||
let conflict_message = "";
|
||||
for (var i = 0; i < between.length; i++) {
|
||||
let courseA = between[i][0];
|
||||
let courseB = between[i][1];
|
||||
conflict_message += `CONFLICT: ${formatShortenedCourseName(courseA)} and ${formatShortenedCourseName(courseB)}`;
|
||||
if (i != between.length - 1) conflict_message += "<br>";
|
||||
}
|
||||
$(Template.Popup.conflict_message(conflict_message)).prependTo("#courseList").hide().fadeIn(200);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/* prettify the name for the conflict messages*/
|
||||
function formatShortenedCourseName(course) {
|
||||
let { number, department } = separateCourseNameParts(course.coursename);
|
||||
return `${department} ${number} (${course.unique})`;
|
||||
}
|
||||
|
||||
$(document).click(function (event) {
|
||||
$target = $(event.target);
|
||||
|
||||
// If we're not clicking on search button or search popup, and popup is visible, hide it
|
||||
if (!$target.closest("#search").length && !$target.closest("#search-popup").length && $("#search-popup").is(":visible")) {
|
||||
hideSearchPopup();
|
||||
}
|
||||
|
||||
// If we're not clicking on import/export button or imp/exp popup, and popup is visible, hide it
|
||||
if (!$target.closest("#impexp").length && !$target.closest("#import-export-popup").length && $("#import-export-popup").is(":visible")) {
|
||||
hideImportExportPopup();
|
||||
}
|
||||
});
|
||||
|
||||
$("#clear").click(function () {
|
||||
chrome.storage.sync.set({
|
||||
savedCourses: [],
|
||||
});
|
||||
$("#courseList").empty();
|
||||
updateAllTabsCourseList();
|
||||
showEmpty();
|
||||
});
|
||||
|
||||
$("#RIS").click(function () {
|
||||
chrome.tabs.create({
|
||||
url: "https://utdirect.utexas.edu/registrar/ris.WBX",
|
||||
});
|
||||
});
|
||||
|
||||
$("#calendar").click(function () {
|
||||
chrome.tabs.create({
|
||||
url: "calendar.html",
|
||||
});
|
||||
});
|
||||
|
||||
$("#impexp").click(function () {
|
||||
if ($("#impexp>i").text() == "close") {
|
||||
hideImportExportPopup();
|
||||
} else {
|
||||
if ($("#search>i").text() == "close") {
|
||||
hideSearchPopup();
|
||||
}
|
||||
showImportExportPopup();
|
||||
}
|
||||
});
|
||||
|
||||
$("#search").click(function () {
|
||||
if ($("#search>i").text() == "close") {
|
||||
hideSearchPopup();
|
||||
} else {
|
||||
if ($("#impexp>i").text() == "close") {
|
||||
hideImportExportPopup();
|
||||
}
|
||||
showSearchPopup();
|
||||
}
|
||||
});
|
||||
|
||||
$("#import-class").click(function () {
|
||||
$("#import_input").click();
|
||||
console.log("back to improting");
|
||||
});
|
||||
|
||||
function isImportedValid(imported_courses) {
|
||||
return imported_courses && imported_courses.length && (imported_courses.length == 0 || validateCourses(imported_courses));
|
||||
}
|
||||
|
||||
$("#import_input").change(function (e) {
|
||||
console.log("hello");
|
||||
var files = e.target.files;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
try {
|
||||
var imported_courses = JSON.parse(this.result);
|
||||
if (isImportedValid(imported_courses)) {
|
||||
chrome.storage.sync.set({
|
||||
savedCourses: imported_courses,
|
||||
});
|
||||
updateAllTabsCourseList();
|
||||
setCourseList();
|
||||
hideImportExportPopup();
|
||||
$("#import_input").val("");
|
||||
} else {
|
||||
Alert("There was an error.");
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
reader.readAsText(files[0]);
|
||||
});
|
||||
|
||||
function exportCourses(url) {
|
||||
var exportlink = document.createElement("a");
|
||||
exportlink.setAttribute("href", url);
|
||||
exportlink.setAttribute("download", "my_courses.json");
|
||||
exportlink.click();
|
||||
}
|
||||
|
||||
function createBlob(export_courses) {
|
||||
return new Blob([JSON.stringify(export_courses, null, 4)], {
|
||||
type: "octet/stream",
|
||||
});
|
||||
}
|
||||
|
||||
$("#export-class").click(function () {
|
||||
chrome.storage.sync.get("savedCourses", function (data) {
|
||||
let export_courses = data.savedCourses;
|
||||
if (export_courses.length > 0) {
|
||||
let url = window.URL.createObjectURL(createBlob(export_courses));
|
||||
exportCourses(url);
|
||||
} else {
|
||||
alert("No Saved Courses to Export.");
|
||||
}
|
||||
hideImportExportPopup();
|
||||
});
|
||||
});
|
||||
|
||||
function openSearch(semester, department, level, courseCode) {
|
||||
var link = "";
|
||||
if (courseCode) {
|
||||
link = `https://utdirect.utexas.edu/apps/registrar/course_schedule/${semester}/results/?search_type_main=COURSE&fos_cn=${department}&course_number=${courseCode}`;
|
||||
} else {
|
||||
link = `https://utdirect.utexas.edu/apps/registrar/course_schedule/${semester}/results/?fos_fl=${department}&level=${level}&search_type_main=FIELD`;
|
||||
}
|
||||
chrome.tabs.create({ url: link });
|
||||
}
|
||||
|
||||
$("#search-class").click(() => {
|
||||
let semester = $("#semesters").find(":selected").val();
|
||||
let department = $("#department").find(":selected").val();
|
||||
let level = $("#level").find(":selected").val();
|
||||
let courseCode = $("#courseCode").val();
|
||||
openSearch(semester, department, level, courseCode);
|
||||
});
|
||||
|
||||
$("#options_button").click(function () {
|
||||
chrome.tabs.create({
|
||||
url: "options.html",
|
||||
});
|
||||
});
|
||||
|
||||
$("#courseList")
|
||||
.on("mouseover", ".copy_button", function () {
|
||||
$(this).addClass("shadow");
|
||||
})
|
||||
.on("mouseleave", ".copy_button", function () {
|
||||
$(this).removeClass("shadow");
|
||||
});
|
||||
|
||||
$("#courseList").on("click", ".copy_button", function (e) {
|
||||
e.stopPropagation();
|
||||
copyButtonAnimation($(this));
|
||||
let unique = $(this).val();
|
||||
copyUnique(unique);
|
||||
});
|
||||
|
||||
function copyUnique(unique) {
|
||||
var temp = $("<input>");
|
||||
$("body").append(temp);
|
||||
temp.val(unique).select();
|
||||
document.execCommand("copy");
|
||||
temp.remove();
|
||||
}
|
||||
|
||||
$("#courseList").on("click", "li", function () {
|
||||
let clicked_item = $(this).closest("li");
|
||||
let curr_course = courses[$(clicked_item).attr("id")];
|
||||
handleMoreInfo(clicked_item, curr_course);
|
||||
handleRegister(clicked_item, curr_course);
|
||||
handleRemove(clicked_item, curr_course);
|
||||
toggleTimeDropdown(clicked_item);
|
||||
});
|
||||
|
||||
function handleRegister(clicked_item, curr_course) {
|
||||
let { status, registerlink } = curr_course;
|
||||
let register_button = $(clicked_item).find("#register");
|
||||
let can_not_register = canNotRegister(status, registerlink);
|
||||
let register_text = can_not_register ? "Can't Register" : status.includes("waitlisted") ? "Join Waitlist" : "Register";
|
||||
let register_color = can_not_register ? Colors.closed : status.includes("waitlisted") ? Colors.waitlisted : Colors.open;
|
||||
|
||||
if (!status) {
|
||||
register_text = "No Status";
|
||||
register_color = Colors.no_status;
|
||||
}
|
||||
|
||||
$(register_button).text(register_text).css("background-color", register_color);
|
||||
|
||||
if (!can_not_register) {
|
||||
$(register_button).click(function () {
|
||||
setCurrentTabUrl(registerlink);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleRemove(clicked_item, curr_course) {
|
||||
let list = $(clicked_item).closest("ul");
|
||||
$(clicked_item)
|
||||
.find("#listRemove")
|
||||
.click(function () {
|
||||
if (can_remove) {
|
||||
can_remove = false;
|
||||
$(list)
|
||||
.find("#conflict")
|
||||
.fadeOut(300, function () {
|
||||
$(clicked_item).remove();
|
||||
});
|
||||
subtractHours(curr_course);
|
||||
chrome.runtime.sendMessage(
|
||||
{
|
||||
command: "courseStorage",
|
||||
course: curr_course,
|
||||
action: "remove",
|
||||
},
|
||||
() => {
|
||||
$(clicked_item).fadeOut(200);
|
||||
if ($(list).children(":visible").length === 1) showEmpty();
|
||||
can_remove = true;
|
||||
updateConflicts();
|
||||
updateAllTabsCourseList();
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function subtractHours(curr_course) {
|
||||
let curr_total_hours = parseInt($("#meta-metric").text());
|
||||
let curr_course_number = separateCourseNameParts(curr_course.coursename).number;
|
||||
let class_length = parseInt(curr_course_number.charAt(0));
|
||||
let multi_semester_code = curr_course_number.slice(-1);
|
||||
if (["A", "B"].includes(multi_semester_code)) {
|
||||
$("#meta-metric").text(curr_total_hours - Math.floor(class_length / 2));
|
||||
} else if (["X", "Y", "Z"].includes(multi_semester_code)) {
|
||||
$("#meta-metric").text(curr_total_hours - Math.floor(class_length / 3));
|
||||
} else {
|
||||
$("#meta-metric").text(curr_total_hours - class_length);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMoreInfo(clicked_item, curr_course) {
|
||||
$(clicked_item)
|
||||
.find("#listMoreInfo")
|
||||
.click(function () {
|
||||
openMoreInfoWithOpenModal(curr_course.link);
|
||||
});
|
||||
}
|
||||
|
||||
function handleEmpty() {
|
||||
if (courses.length != 0) {
|
||||
$("#empty").hide();
|
||||
$("#courseList").show();
|
||||
} else {
|
||||
showEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
function copyButtonAnimation(copy_button) {
|
||||
$(copy_button).find("i").text("check");
|
||||
$(copy_button).stop(true, false).removeAttr("style").removeClass("shadow", {
|
||||
duration: 200,
|
||||
});
|
||||
$(copy_button)
|
||||
.find("i")
|
||||
.delay(400)
|
||||
.queue(function (n) {
|
||||
$(this).text("content_copy");
|
||||
$(this).parent().removeClass("shadow");
|
||||
if ($(this).parent().is(":hover")) {
|
||||
$(this).parent().addClass("shadow");
|
||||
}
|
||||
n();
|
||||
});
|
||||
}
|
||||
|
||||
function toggleTimeDropdown(clicked_item) {
|
||||
let more_info_button = $(clicked_item).find("#moreInfo");
|
||||
let arrow = $(clicked_item).find("#arrow");
|
||||
if ($(more_info_button).is(":hidden")) {
|
||||
$(more_info_button).fadeIn(200);
|
||||
$(arrow).css("transform", "rotate(90deg)");
|
||||
} else {
|
||||
$(more_info_button).fadeOut(200);
|
||||
$(arrow).css("transform", "");
|
||||
}
|
||||
}
|
||||
|
||||
function showEmpty() {
|
||||
$("#courseList").hide();
|
||||
$("#empty").fadeIn(200);
|
||||
$("#main").html(Text.emptyText());
|
||||
$("#meta-metric").text("0");
|
||||
}
|
||||
|
||||
function hideSearchPopup() {
|
||||
$("#search>i").text("search");
|
||||
$("#semcon").hide();
|
||||
$("#depcon").hide();
|
||||
$("#semesters").hide();
|
||||
$("#levcon").hide();
|
||||
$("#search-popup").addClass("hide");
|
||||
}
|
||||
|
||||
function showSearchPopup() {
|
||||
$("#search>i").text("close");
|
||||
$("#class_id_input").show();
|
||||
$("#semesters").show();
|
||||
$("#semcon").show();
|
||||
$("#depcon").show();
|
||||
$("#levcon").show();
|
||||
$("#search-popup").removeClass("hide");
|
||||
}
|
||||
|
||||
function hideImportExportPopup() {
|
||||
$("#import-export-popup").addClass("hide");
|
||||
$("#impexp>i").text("import_export");
|
||||
}
|
||||
|
||||
function showImportExportPopup() {
|
||||
$("#impexp>i").text("close");
|
||||
$("#import-export-popup").removeClass("hide");
|
||||
}
|
||||
|
||||
function getSemesters() {
|
||||
chrome.runtime.sendMessage(
|
||||
{
|
||||
command: "currentSemesters",
|
||||
},
|
||||
function (response) {
|
||||
let { semesters } = response;
|
||||
let semester_names = Object.keys(semesters);
|
||||
for (let i = 0; i < semester_names.length; i++) {
|
||||
let name = semester_names[i];
|
||||
$("#semesters").append(`<option value='${semesters[name]}'>${name}</option>`);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getDepartments() {
|
||||
chrome.runtime.sendMessage(
|
||||
{
|
||||
command: "currentDepartments",
|
||||
},
|
||||
function (response) {
|
||||
let { departments } = response;
|
||||
console.log(departments);
|
||||
for (let i = 0; i < departments.length; i++) {
|
||||
let abv = departments[i];
|
||||
$("#department").append(`<option value='${abv}'>${abv}</option>`);
|
||||
}
|
||||
// $("#department").val('C S');
|
||||
}
|
||||
);
|
||||
}
|
||||
242
js/utPlanner.js
@@ -1,242 +0,0 @@
|
||||
let semester_code = "";
|
||||
curr_course = {}
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
command: "currentSemesters"
|
||||
}, function(response){
|
||||
let semester_text = $('.row:contains(Semester)').find('span').text();
|
||||
let key = semester_text.split(' ').reverse().join(' ');
|
||||
semester_code = response.semesters[key];
|
||||
});
|
||||
|
||||
$.initialize("table.section-detail-grid", function () {
|
||||
$(this).find('thead>tr').append('<th> Plus</th')
|
||||
$(this).find('tbody>tr').each(function () {
|
||||
$(this).append(Template.Main.extension_button());
|
||||
})
|
||||
});
|
||||
|
||||
$("body").prepend(Template.UTPlanner.modal());
|
||||
$("body").on('click', '#distButton', function () {
|
||||
var row = $(this).closest('tr');
|
||||
$('.modal-content').stop().animate({ scrollTop: 0 }, 500);
|
||||
$(this).blur();
|
||||
getCourseInfo(row)
|
||||
});
|
||||
|
||||
|
||||
function getCourseInfo(row) {
|
||||
let rowdata = $(row).find('td').slice(3).toArray().map(x => $(x).text().trim());
|
||||
let [uniquenum, department, coursenum, coursename, profname, notes, rawtime] = rowdata
|
||||
let profinit = ""
|
||||
if (profname !== undefined && profname != "Staff") {
|
||||
profinit = profname.split(',')[1].trim();
|
||||
profname = profname.split(',')[0].trim();
|
||||
}
|
||||
let times = rawtime.split('\n').map(x => x.trim());
|
||||
var course_data = {
|
||||
"unique": uniquenum,
|
||||
"department": department,
|
||||
"number": coursenum,
|
||||
"name": coursename,
|
||||
"prof_name": profname,
|
||||
"initial": profinit,
|
||||
"notes": notes,
|
||||
"individual": `https://utdirect.utexas.edu/apps/registrar/course_schedule/${semester_code}/${uniquenum}/`,
|
||||
"times": times,
|
||||
}
|
||||
curr_course = buildCourseLinks(course_data);
|
||||
getDistribution(course_data);
|
||||
var modal = document.getElementById('myModal');
|
||||
window.onclick = function (event) {
|
||||
if (event.target == modal) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildCourseLinks(course_info) {
|
||||
console.log(semester_code);
|
||||
let {
|
||||
department,
|
||||
number,
|
||||
unique,
|
||||
prof_name
|
||||
} = course_info
|
||||
links = {
|
||||
"textbook": `https://www.universitycoop.com/adoption-search-results?sn=${semester_code}__${department}__${number}__${unique}`,
|
||||
"syllabi": `https://utdirect.utexas.edu/apps/student/coursedocs/nlogon/?year=&semester=&department=${department}&course_number=${number}&course_title=&unique=&instructor_first=&instructor_last=${prof_name}&course_type=In+Residence&search=Search`,
|
||||
}
|
||||
course_info["links"] = links;
|
||||
return course_info;
|
||||
}
|
||||
|
||||
function badData(course_data, res) {
|
||||
return typeof res == 'undefined' || course_data["prof_name"] == "Staff";
|
||||
}
|
||||
|
||||
$("#semesters").on('change', function () {
|
||||
var sem = $(this).val();
|
||||
sem = sem == "Aggregate" ? undefined : sem;
|
||||
getDistribution(curr_course, sem);
|
||||
});
|
||||
|
||||
$("#Syllabi").click(function () {
|
||||
setTimeout(function () {
|
||||
window.open(curr_course["links"]["syllabi"]);
|
||||
}, Timing.button_delay);
|
||||
});
|
||||
$("#textbook").click(function () {
|
||||
setTimeout(function () {
|
||||
window.open(curr_course["links"]["textbook"]);
|
||||
}, Timing.button_delay);
|
||||
});
|
||||
|
||||
$("#moreInfo").click(function () {
|
||||
openMoreInfoWithOpenModal(curr_course["individual"]);
|
||||
});
|
||||
|
||||
|
||||
function toggleChartLoading(loading) {
|
||||
if (loading) {
|
||||
$('#chartload').css('display', 'inline-block');
|
||||
$("#chart").hide();
|
||||
} else {
|
||||
$('#chartload').hide();
|
||||
$("#chart").show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function openDialog(course_data, res) {
|
||||
console.log(course_data);
|
||||
$("#title").text(buildTitle(course_data))
|
||||
$("#topbuttons").before(buildTimeTitle(course_data["times"]));
|
||||
$("#profname").text(buildProfTitle(course_data));
|
||||
$("#myModal").fadeIn(Timing.fade_time);
|
||||
buildSemestersDropdown(course_data, res)
|
||||
var data = []
|
||||
if (!badData(course_data, res))
|
||||
data = res.values[0];
|
||||
setChart(data);
|
||||
allowClosing();
|
||||
}
|
||||
|
||||
function buildProfTitle(course_data) {
|
||||
const {
|
||||
initial,
|
||||
prof_name
|
||||
} = course_data;
|
||||
return `with ${initial?initial+". ":""}${prof_name}`;
|
||||
}
|
||||
|
||||
function buildSemestersDropdown(course_data, res) {
|
||||
$("#semesters").empty();
|
||||
if (badData(course_data, res)) {
|
||||
$("#semesters").append("<option>No Data</option>")
|
||||
} else {
|
||||
var semesters = res.values[0][18].split(",");
|
||||
semesters.sort(semesterSort);
|
||||
semesters.reverse().unshift('Aggregate');
|
||||
var sems = [];
|
||||
for (var i = 0; i < semesters.length; i++) {
|
||||
sems.push($(`<option value="${semesters[i]}">${semesters[i]}</option>`));
|
||||
}
|
||||
$("#semesters").append(sems);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*Query the grades database*/
|
||||
function getDistribution(course_data, sem) {
|
||||
toggleChartLoading(true);
|
||||
let query = buildQuery(course_data, sem);
|
||||
chrome.runtime.sendMessage({
|
||||
command: "gradesQuery",
|
||||
query: query
|
||||
}, function (response) {
|
||||
var res = response.data;
|
||||
if (!sem) {
|
||||
openDialog(course_data, res);
|
||||
} else {
|
||||
var data = badData(course_data, res) ? [] : res.values[0];
|
||||
setChart(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function buildTitle(course_data) {
|
||||
return `${course_data["name"]} (${course_data["department"]} ${course_data["number"]})`
|
||||
}
|
||||
|
||||
|
||||
function buildTimeTitle(times) {
|
||||
$("h2.dateTimePlace").remove();
|
||||
var lines = []
|
||||
for (var i = 0; i < times.length; i++) {
|
||||
date = times[i].substring(0, times[i].indexOf(' ')).toUpperCase();
|
||||
time = times[i].substring(times[i].indexOf(' ') + 1, times[i].lastIndexOf('-')).trim();
|
||||
place = times[i].substring(times[i].lastIndexOf('-') + 1).trim();
|
||||
lines.push($(`<h2 class="dateTimePlace">${makeLine(date, time, place)}</th>`));
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
function makeLine(date, time, place) {
|
||||
var arr = separateDays(date)
|
||||
var output = prettifyDaysText(arr)
|
||||
var building = place.substring(0, place.search(/\d/) - 1);
|
||||
building = building == "" ? "Undecided Location" : building;
|
||||
return `${output} at ${time.replace(/\./g, '').replace(/\-/g, ' to ')} in <a style='font-size:medium' target='_blank' href='https://maps.utexas.edu/buildings/UTM/${building}'>${building}</>`;
|
||||
}
|
||||
|
||||
function setChart(data) {
|
||||
//set up the chart
|
||||
toggleChartLoading(false);
|
||||
chart = Highcharts.chart('chart', buildChartConfig(data), function (chart) { // on complete
|
||||
if (data.length == 0) {
|
||||
//if no data, then show the message and hide the series
|
||||
chart.renderer.text('Could not find data for this Instructor teaching this Course.', 100, 120)
|
||||
.css({
|
||||
fontSize: '20px',
|
||||
width: '300px',
|
||||
align: 'center',
|
||||
left: '160px'
|
||||
})
|
||||
.add();
|
||||
$.each(chart.series, function (i, ser) {
|
||||
ser.hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function standardizeName(department, number, name){
|
||||
return `${department} ${number} ${name}`
|
||||
|
||||
}
|
||||
|
||||
function allowClosing() {
|
||||
$('.close').click(function () {
|
||||
close();
|
||||
});
|
||||
$('#myModal').click(function (event) {
|
||||
if (event.target.id == 'myModal') {
|
||||
close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
$("#myModal").fadeOut(Timing.fade_time);
|
||||
$("#snackbar").attr("class", "");
|
||||
}
|
||||
|
||||
|
||||
$(document).keydown(function (e) {
|
||||
/*Close Modal when hit escape*/
|
||||
if (e.keyCode == 27) {
|
||||
close();
|
||||
}
|
||||
});
|
||||
386
js/util.js
@@ -1,386 +0,0 @@
|
||||
const days = new Map([
|
||||
["M", "Monday"],
|
||||
["T", "Tuesday"],
|
||||
["W", "Wednesday"],
|
||||
["TH", "Thursday"],
|
||||
["F", "Friday"]
|
||||
]);
|
||||
|
||||
function getStatusColor(status, sub = false) {
|
||||
let color = "black";
|
||||
if (status.includes("open")) {
|
||||
color = sub ? Colors.open_light : Colors.open;
|
||||
} else if (status.includes("waitlisted")) {
|
||||
color = sub ? Colors.waitlisted_light : Colors.waitlisted;
|
||||
} else if (status.includes("closed") || status.includes("cancelled")) {
|
||||
color = sub ? Colors.closed_light : Colors.closed;
|
||||
} else {
|
||||
color = sub ? Colors.no_status_light : Colors.no_status;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
function buildQuery(course_data, sem) {
|
||||
let query = !sem ? "select * from agg" : "select * from grades";
|
||||
query += " where dept like '%" + course_data["department"] + "%'";
|
||||
query += " and prof like '%" + course_data["prof_name"].replace(/'/g, "") + "%'";
|
||||
query += " and course_nbr like '%" + course_data["number"] + "%'";
|
||||
if (sem) {
|
||||
query += "and sem like '%" + sem + "%'";
|
||||
}
|
||||
return query + "order by a1+a2+a3+b1+b2+b3+c1+c2+c3+d1+d2+d3+f desc";
|
||||
}
|
||||
|
||||
/*Course object for passing to background*/
|
||||
function Course(coursename, unique, profname, datetimearr, status, link, registerlink) {
|
||||
this.coursename = coursename;
|
||||
this.unique = unique;
|
||||
this.profname = profname;
|
||||
this.datetimearr = datetimearr;
|
||||
this.status = status;
|
||||
this.link = link;
|
||||
this.registerlink = registerlink;
|
||||
}
|
||||
|
||||
function capitalizeString(string) {
|
||||
//if one word, and if multiple words:
|
||||
let output = "";
|
||||
words = string.split(/[. ,\/ -]/);
|
||||
for (let i in words) {
|
||||
word = words[i];
|
||||
capitalizedWord = word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
||||
output += capitalizedWord + " ";
|
||||
}
|
||||
return output.trim();
|
||||
}
|
||||
|
||||
function separateCourseNameParts(name) {
|
||||
let num_index = name.search(/\d/);
|
||||
department = name.substring(0, num_index).trim();
|
||||
number = name.substring(num_index, name.indexOf(" ", num_index)).trim();
|
||||
name = capitalizeString(name.substring(name.indexOf(" ", num_index)).trim());
|
||||
return {
|
||||
name: name,
|
||||
department: department,
|
||||
number: number
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function separateDays(date, simple=false) {
|
||||
let arr = [];
|
||||
for (var i = 0; i < date.length; i++) {
|
||||
let letter = date.charAt(i);
|
||||
let separated_letter = letter;
|
||||
if (letter == "T" && i < date.length - 1 && date.charAt(i + 1) == "H") {
|
||||
arr.push(simple ? "TH" : days.get("TH"));
|
||||
} else {
|
||||
if (letter != "H") {
|
||||
arr.push(simple ? letter : days.get(letter));
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
/*Convert time to 24hour format*/
|
||||
function convertTime(time) {
|
||||
var converted = time.replace(/\./g, '').split("-");
|
||||
for (var i = 0; i < 2; i++) {
|
||||
converted[i] = moment(converted[i], ["h:mm A"]).format("HH:mm");
|
||||
}
|
||||
return converted;
|
||||
}
|
||||
|
||||
function prettifyDaysText(arr) {
|
||||
var output = "";
|
||||
if (arr.length > 2) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (i < arr.length - 1)
|
||||
output += arr[i] + ", "
|
||||
if (i == arr.length - 2)
|
||||
output += "and ";
|
||||
if (i == arr.length - 1)
|
||||
output += arr[i];
|
||||
}
|
||||
} else if (arr.length == 2) {
|
||||
output = arr[0] + " and " + arr[1];
|
||||
} else {
|
||||
output = arr[0];
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function isIndividualCoursePage(){
|
||||
return $("#textbook_button").length != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function updateAllTabsCourseList() {
|
||||
chrome.tabs.query({}, function (tabs) {
|
||||
for (var i = 0; i < tabs.length; i++) {
|
||||
chrome.tabs.sendMessage(tabs[i].id, {
|
||||
command: "updateCourseList"
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function htmlToNode(response) {
|
||||
return $('<div/>').html(response).contents();
|
||||
}
|
||||
|
||||
function setCurrentTabUrl(link) {
|
||||
chrome.tabs.query({
|
||||
currentWindow: true,
|
||||
active: true
|
||||
}, function (tab) {
|
||||
chrome.tabs.update(tab.id, {
|
||||
url: link
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openMoreInfoWithOpenModal(link){
|
||||
chrome.runtime.sendMessage({ command: "setOpen", url: link });
|
||||
}
|
||||
|
||||
|
||||
function semesterSort(semA, semB) {
|
||||
let semOrder = {
|
||||
"Spring": 0,
|
||||
"Fall": 1,
|
||||
"Summer": 2,
|
||||
"Winter": 3
|
||||
}
|
||||
let aName = semA.split(' ')[0];
|
||||
let aYear = parseInt(semA.split(' ')[1]);
|
||||
let bName = semB.split(' ')[0];
|
||||
let bYear = parseInt(semB.split(' ')[1]);
|
||||
if (aYear < bYear)
|
||||
return -1;
|
||||
if (aYear > bYear)
|
||||
return 1;
|
||||
if (semOrder[aName] < semOrder[bName])
|
||||
return -1;
|
||||
if (semOrder[aName] > semOrder[bName])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* convert from the dtarr and maek the time lines*/
|
||||
function convertDateTimeArrToLine(datetimearr) {
|
||||
var output = [];
|
||||
var dtmap = makeDateTimeMap(datetimearr);
|
||||
var timearr = Array.from(dtmap.keys());
|
||||
var temporary = Array.from(dtmap.values())
|
||||
var dayarr = []
|
||||
var locarr = []
|
||||
for(x in temporary) {
|
||||
dayarr.push(temporary[x][0])
|
||||
locarr.push(temporary[x][1])
|
||||
}
|
||||
|
||||
for (var i = 0; i < dayarr.length; i++) {
|
||||
//var place = findLocation(dayarr[i], timearr[i], datetimearr);
|
||||
var place = locarr[i]
|
||||
var building = place.substring(0, place.search(/\d/)).trim();
|
||||
building = building ? building : "Undecided Location"
|
||||
var timearrsplit = timearr[i].split(',')
|
||||
output.push({
|
||||
"days": dayarr[i],
|
||||
"start_time": timearrsplit[0],
|
||||
"end_time": timearrsplit[1],
|
||||
"location_link": `https://maps.utexas.edu/buildings/UTM/${building}`,
|
||||
"location_full": place
|
||||
})
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function makeDateTimeMap(datetimearr) {
|
||||
var dtmap = new Map([]);
|
||||
for (var i = 0; i < datetimearr.length; i++) {
|
||||
datetimearr[i][1][0] = moment(datetimearr[i][1][0], ["HH:mm A"]).format("h:mm A");
|
||||
datetimearr[i][1][1] = moment(datetimearr[i][1][1], ["HH:mm A"]).format("h:mm A");
|
||||
}
|
||||
for (var i = 0; i < datetimearr.length; i++) {
|
||||
var instance = datetimearr[i]
|
||||
var day = String(instance[0])
|
||||
var timeslot = String(instance[1])
|
||||
var location = String(instance[2])
|
||||
var key = timeslot + "," + location
|
||||
if (dtmap.has(key) && dtmap.get(key)[1] === location) {
|
||||
dtmap.set(key, [dtmap.get(key)[0] + day, location]);
|
||||
} else {
|
||||
dtmap.set(key, [day, location]);
|
||||
}
|
||||
}
|
||||
return dtmap
|
||||
}
|
||||
//find the location of a class given its days and timearrs.
|
||||
function findLocation(day, timearr, datetimearr) {
|
||||
for (let i = 0; i < datetimearr.length; i++) {
|
||||
var dtl = datetimearr[i];
|
||||
if (day.includes(dtl[0])) {
|
||||
if (JSON.stringify(timearr) == JSON.stringify(reformatDateTime(dtl[1]))) {
|
||||
return dtl[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function validateCourses(courses) {
|
||||
for (var i = 0; i < courses.length; i++) {
|
||||
if (!validateCourseObject(courses[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateCourseObject(course) {
|
||||
var is_valid = true;
|
||||
var props = ["coursename", "datetimearr", "link", "profname", "status", "unique"];
|
||||
for (let j = 0; j < props.length; j++) {
|
||||
is_valid &= course.hasOwnProperty(props[j]);
|
||||
}
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
|
||||
function reformatDateTime(dtl1) {
|
||||
let output = "";
|
||||
for (let i = 0; i < dtl1.length; i++) {
|
||||
output += dtl1[i];
|
||||
if (i != dtl1.length - 1) {
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function rgb2hex(rgb) {
|
||||
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
||||
|
||||
function hex(x) {
|
||||
return ("0" + parseInt(x).toString(16)).slice(-2);
|
||||
}
|
||||
return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
|
||||
}
|
||||
|
||||
function buildChartConfig(data) {
|
||||
return {
|
||||
chart: {
|
||||
type: 'column',
|
||||
backgroundColor: ' #fefefe',
|
||||
spacingLeft: 10
|
||||
},
|
||||
title: {
|
||||
text: null
|
||||
},
|
||||
subtitle: {
|
||||
text: null
|
||||
},
|
||||
legend: {
|
||||
enabled: false
|
||||
},
|
||||
xAxis: {
|
||||
title: {
|
||||
text: 'Grades'
|
||||
},
|
||||
categories: [
|
||||
'A',
|
||||
'A-',
|
||||
'B+',
|
||||
'B',
|
||||
'B-',
|
||||
'C+',
|
||||
'C',
|
||||
'C-',
|
||||
'D+',
|
||||
'D',
|
||||
'D-',
|
||||
'F'
|
||||
],
|
||||
crosshair: true
|
||||
},
|
||||
yAxis: {
|
||||
min: 0,
|
||||
title: {
|
||||
text: 'Students'
|
||||
}
|
||||
},
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
lang: {
|
||||
noData: "The professor hasn't taught this class :("
|
||||
},
|
||||
tooltip: {
|
||||
headerFormat: '<span style="font-size:small; font-weight:bold">{point.key}</span><table>',
|
||||
pointFormat: '<td style="color:{black};padding:0;font-size:small; font-weight:bold;"><b>{point.y:.0f} Students</b></td>',
|
||||
footerFormat: '</table>',
|
||||
shared: true,
|
||||
useHTML: true
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
pointPadding: 0.2,
|
||||
borderWidth: 0
|
||||
},
|
||||
series: {
|
||||
animation: {
|
||||
duration: 700
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: 'Grades',
|
||||
data: [{
|
||||
y: data[6],
|
||||
color: '#4CAF50'
|
||||
}, {
|
||||
y: data[7],
|
||||
color: '#8BC34A'
|
||||
}, {
|
||||
y: data[8],
|
||||
color: '#CDDC39'
|
||||
}, {
|
||||
y: data[9],
|
||||
color: '#FFEB3B'
|
||||
}, {
|
||||
y: data[10],
|
||||
color: '#FFC107'
|
||||
}, {
|
||||
y: data[11],
|
||||
color: '#FFA000'
|
||||
}, {
|
||||
y: data[12],
|
||||
color: '#F57C00'
|
||||
}, {
|
||||
y: data[13],
|
||||
color: '#FF5722'
|
||||
}, {
|
||||
y: data[14],
|
||||
color: '#FF5252'
|
||||
}, {
|
||||
y: data[15],
|
||||
color: '#E64A19'
|
||||
}, {
|
||||
y: data[16],
|
||||
color: '#F44336'
|
||||
}, {
|
||||
y: data[17],
|
||||
color: '#D32F2F'
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
function canNotRegister(status, register_link) {
|
||||
return status.includes("closed") || status.includes("cancelled") || !status || !register_link
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "UT Registration Plus",
|
||||
"version": "1.2.2.7",
|
||||
"options_page": "options.html",
|
||||
"description": "Improves the course registration process at the University of Texas at Austin!",
|
||||
"permissions": [
|
||||
"storage",
|
||||
"*://*.utdirect.utexas.edu/apps/registrar/course_schedule/*",
|
||||
"*://*.utexas.collegescheduler.com/*",
|
||||
"*://*.catalog.utexas.edu/ribbit/",
|
||||
"*://*.registrar.utexas.edu/schedules/*",
|
||||
"*://*.login.utexas.edu/login/*"
|
||||
],
|
||||
"content_scripts": [
|
||||
{
|
||||
"css": ["css/styles.css"],
|
||||
"js": [
|
||||
"js/config.js",
|
||||
"js/lib/moment.min.js",
|
||||
"js/lib/highcharts.js",
|
||||
"js/lib/jquery-3.3.1.min.js",
|
||||
"js/lib/jquery.initialize.min.js",
|
||||
"js/util.js",
|
||||
"js/Template.js",
|
||||
"js/courseCatalog.js"
|
||||
],
|
||||
"matches": ["https://utdirect.utexas.edu/apps/registrar/course_schedule/*"]
|
||||
},
|
||||
{
|
||||
"css": ["css/styles.css"],
|
||||
"js": [
|
||||
"js/config.js",
|
||||
"js/lib/moment.min.js",
|
||||
"js/lib/highcharts.js",
|
||||
"js/lib/jquery-3.3.1.min.js",
|
||||
"js/lib/jquery.initialize.min.js",
|
||||
"js/util.js",
|
||||
"js/Template.js",
|
||||
"js/utPlanner.js"
|
||||
],
|
||||
"matches": ["https://utexas.collegescheduler.com/*"]
|
||||
},
|
||||
{
|
||||
"css": ["css/styles.css"],
|
||||
"js": ["js/config.js", "js/lib/moment.min.js", "js/lib/highcharts.js", "js/lib/jquery-3.3.1.min.js", "js/Template.js", "js/util.js", "js/import.js"],
|
||||
"matches": ["https://utdirect.utexas.edu/registrar/waitlist/wl_see_my_waitlists.WBX", "https://utdirect.utexas.edu/registration/classlist.WBX*"]
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": ["grades.db", "images/disticon.png"],
|
||||
"background": {
|
||||
"scripts": ["js/lib/jquery-3.3.1.min.js", "js/lib/sql-memory-growth.js", "js/lib/moment.min.js", "js/config.js", "js/util.js", "js/background.js"],
|
||||
"persistent": true
|
||||
},
|
||||
"browser_action": {
|
||||
"default_popup": "popup.html",
|
||||
"default_icon": {
|
||||
"16": "icons/icon16.png",
|
||||
"32": "icons/icon32.png",
|
||||
"48": "icons/icon48.png",
|
||||
"128": "icons/icon128.png"
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"16": "icons/icon16.png",
|
||||
"32": "icons/icon32.png",
|
||||
"48": "icons/icon48.png",
|
||||
"128": "icons/icon128.png"
|
||||
}
|
||||
}
|
||||
30
options.html
@@ -1,30 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!-- This file is serving as the template for the options page -->
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="css/options.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="version-container">
|
||||
<p class="version">(v<span id="version"></span>)</p>
|
||||
</div>
|
||||
<div class="card options-card" id="header">
|
||||
<h2 class="options-header"><u>Options</u></h2>
|
||||
<div id="options_container"></div>
|
||||
<p class="creator-tag"><a href="https://sghsri.github.io">Sriram Hariharan</a> (2018)</p>
|
||||
</div>
|
||||
<div class="card options-card" id="contributors_container">
|
||||
<h3 class="contributor-title">Amazing people who've contributed to the extension!</h3>
|
||||
<p class="creator-tag open-source-tag">Code is open source here <a href="https://github.com/sghsri/UT-Registration-Plus">here</a> :)</p>
|
||||
<div id="contributor-list"></div>
|
||||
</div>
|
||||
<script src="js/config.js"></script>
|
||||
<script src="js/lib/jquery-3.3.1.min.js"></script>
|
||||
<script src="js/util.js"></script>
|
||||
<script src="js/Template.js"></script>
|
||||
<script src="js/options.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
168
package.json
Normal file
@@ -0,0 +1,168 @@
|
||||
{
|
||||
"name": "ut-registration-plus",
|
||||
"displayName": "UT Registration Plus",
|
||||
"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",
|
||||
"type": "module",
|
||||
"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": "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",
|
||||
"lint:fix": "eslint src --ext ts,tsx --report-unused-disable-directives --fix",
|
||||
"check-types": "tsc --noEmit",
|
||||
"test": "vitest",
|
||||
"test:ui": "vitest --ui",
|
||||
"coverage": "vitest run --coverage",
|
||||
"preview": "vite preview",
|
||||
"generate-changelog": "bun run scripts/generateChangelog.ts",
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build",
|
||||
"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",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@headlessui/react": "^2.2.0",
|
||||
"@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",
|
||||
"husky": "^9.1.7",
|
||||
"kc-dabr-wasm": "^0.1.2",
|
||||
"nanoid": "^5.1.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-loading-skeleton": "^3.5.0",
|
||||
"react-markdown": "^9.1.0",
|
||||
"react-syntax-highlighter": "^15.6.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"sass": "^1.85.1",
|
||||
"simple-git": "^3.27.0",
|
||||
"sql.js": "1.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chromatic-com/storybook": "^2.0.2",
|
||||
"@commitlint/cli": "^19.7.1",
|
||||
"@commitlint/config-conventional": "^19.7.1",
|
||||
"@commitlint/types": "^19.5.0",
|
||||
"@crxjs/vite-plugin": "2.0.0-beta.21",
|
||||
"@iconify-json/bi": "^1.2.2",
|
||||
"@iconify-json/ic": "^1.2.2",
|
||||
"@iconify-json/iconoir": "^1.2.7",
|
||||
"@iconify-json/material-symbols": "^1.2.14",
|
||||
"@iconify-json/ri": "^1.2.5",
|
||||
"@iconify-json/streamline": "^1.2.2",
|
||||
"@semantic-release/exec": "^6.0.3",
|
||||
"@sentry/types": "^8.55.0",
|
||||
"@storybook/addon-designs": "^8.2.0",
|
||||
"@storybook/addon-essentials": "^8.6.0",
|
||||
"@storybook/addon-links": "^8.6.0",
|
||||
"@storybook/blocks": "^8.6.0",
|
||||
"@storybook/react": "^8.6.0",
|
||||
"@storybook/react-vite": "^8.6.0",
|
||||
"@storybook/test": "^8.6.0",
|
||||
"@svgr/core": "^8.1.0",
|
||||
"@svgr/plugin-jsx": "^8.1.0",
|
||||
"@types/chrome": "^0.0.273",
|
||||
"@types/conventional-changelog": "^3.1.5",
|
||||
"@types/gulp": "^4.0.17",
|
||||
"@types/gulp-zip": "^4.0.4",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"@types/react": "^18.3.18",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@types/semantic-release": "^20.0.6",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/sql.js": "^1.4.9",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@unocss/eslint-config": "^0.63.6",
|
||||
"@unocss/postcss": "^0.63.6",
|
||||
"@unocss/preset-uno": "^0.63.6",
|
||||
"@unocss/preset-web-fonts": "^0.63.6",
|
||||
"@unocss/reset": "^0.63.6",
|
||||
"@unocss/transformer-directives": "^0.63.6",
|
||||
"@unocss/transformer-variant-group": "^0.63.6",
|
||||
"@vitejs/plugin-react-swc": "^3.8.0",
|
||||
"@vitest/coverage-v8": "^2.1.9",
|
||||
"@vitest/ui": "^2.1.9",
|
||||
"chalk": "^5.4.1",
|
||||
"chromatic": "^11.26.0",
|
||||
"cssnano": "^7.0.6",
|
||||
"cssnano-preset-advanced": "^7.0.6",
|
||||
"dotenv": "^16.4.7",
|
||||
"es-module-lexer": "^1.6.0",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-config-airbnb-typescript": "^18.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-typescript": "^3.8.3",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-import-essentials": "^0.2.1",
|
||||
"eslint-plugin-jsdoc": "^50.6.3",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-prefer-function-component": "^3.4.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"eslint-plugin-storybook": "^0.9.0",
|
||||
"eslint-plugin-tsdoc": "^0.3.0",
|
||||
"gulp": "^5.0.0",
|
||||
"gulp-execa": "^7.0.1",
|
||||
"gulp-zip": "^6.1.0",
|
||||
"path": "^0.12.7",
|
||||
"postcss": "^8.5.3",
|
||||
"prettier": "^3.5.2",
|
||||
"react-dev-utils": "^12.0.1",
|
||||
"semantic-release": "^24.2.3",
|
||||
"storybook": "^8.6.0",
|
||||
"typescript": "^5.7.3",
|
||||
"unocss": "^0.63.6",
|
||||
"unocss-preset-primitives": "0.0.2-beta.1",
|
||||
"unplugin-icons": "^0.19.3",
|
||||
"vite": "^5.4.20",
|
||||
"vite-plugin-inspect": "^0.8.9",
|
||||
"vitest": "^2.1.9"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"engines": {
|
||||
"pnpm": "^10"
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"@crxjs/vite-plugin@2.0.0-beta.21": "patches/@crxjs__vite-plugin@2.0.0-beta.21.patch",
|
||||
"@unocss/vite": "patches/@unocss__vite.patch"
|
||||
},
|
||||
"overrides": {
|
||||
"es-module-lexer": "^1.5.4"
|
||||
}
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.19.4",
|
||||
"pnpm": "10.14.0"
|
||||
}
|
||||
}
|
||||
105
patches/@crxjs__vite-plugin@2.0.0-beta.21.patch
Normal file
@@ -0,0 +1,105 @@
|
||||
diff --git a/dist/index.mjs b/dist/index.mjs
|
||||
index 5c3f6291168987c56b816428080e6f1fe9de7107..abaf6290fe9454ae036a81eacbe7dc3be2fdfbc3 100644
|
||||
--- a/dist/index.mjs
|
||||
+++ b/dist/index.mjs
|
||||
@@ -499,16 +499,43 @@ ${sourceMap}
|
||||
}),
|
||||
mergeMap(async ({ target, code, deps }) => {
|
||||
await lexer.init;
|
||||
- const [imports] = lexer.parse(code, fileName);
|
||||
+ const [imports, exports] = lexer.parse(code, fileName);
|
||||
const depSet = new Set(deps);
|
||||
const magic = new MagicString(code);
|
||||
- for (const i of imports)
|
||||
+ for (const i of imports) {
|
||||
if (i.n) {
|
||||
depSet.add(i.n);
|
||||
const fileName2 = getFileName({ type: "module", id: i.n });
|
||||
const fullImport = code.substring(i.s, i.e);
|
||||
- magic.overwrite(i.s, i.e, fullImport.replace(i.n, `/${fileName2}`));
|
||||
+ const hmrTimestamp = fullImport.match(/\bt=\d{13}&?\b/);
|
||||
+ magic.overwrite(
|
||||
+ i.s,
|
||||
+ i.e,
|
||||
+ fullImport.replace(
|
||||
+ i.n,
|
||||
+ `/${fileName2}${hmrTimestamp ? `?${hmrTimestamp[0]}` : ""}`
|
||||
+ )
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+ for (const e of exports) {
|
||||
+ if (e.n === "default") {
|
||||
+ const regex = /\s+['"](.*)['"]/y;
|
||||
+ regex.lastIndex = e.e;
|
||||
+ const fullExport = regex.exec(code)?.[1];
|
||||
+ if (!fullExport)
|
||||
+ continue;
|
||||
+ const start = regex.lastIndex - fullExport.length - 1;
|
||||
+ const end = regex.lastIndex - 1;
|
||||
+ if (fullExport.startsWith("/node_modules")) {
|
||||
+ magic.overwrite(
|
||||
+ start,
|
||||
+ end,
|
||||
+ `http://localhost:5173${fullExport}`
|
||||
+ );
|
||||
+ }
|
||||
}
|
||||
+ }
|
||||
return { target, source: magic.toString(), deps: [...depSet] };
|
||||
})
|
||||
);
|
||||
@@ -1229,10 +1256,14 @@ const pluginHMR = () => {
|
||||
handleHotUpdate({ modules, server }) {
|
||||
const { root } = server.config;
|
||||
const relFiles = /* @__PURE__ */ new Set();
|
||||
- for (const m of modules)
|
||||
+ function getRelFile(file) {
|
||||
+ return file.startsWith(root) ? file.slice(server.config.root.length) : file;
|
||||
+ }
|
||||
+ for (const m of modules) {
|
||||
if (m.id?.startsWith(root)) {
|
||||
relFiles.add(m.id.slice(server.config.root.length));
|
||||
}
|
||||
+ }
|
||||
if (inputManifestFiles.background.length) {
|
||||
const background = prefix$1("/", inputManifestFiles.background[0]);
|
||||
if (relFiles.has(background) || modules.some(isImporter(join(server.config.root, background)))) {
|
||||
@@ -1244,7 +1275,14 @@ const pluginHMR = () => {
|
||||
for (const [key, script] of contentScripts)
|
||||
if (key === script.id) {
|
||||
if (relFiles.has(script.id) || modules.some(isImporter(join(server.config.root, script.id)))) {
|
||||
- relFiles.forEach((relFile) => update(relFile));
|
||||
+ modules.filter((mod) => mod.id?.startsWith(root)).forEach((mod) => {
|
||||
+ update(getRelFile(mod.id));
|
||||
+ if (mod.file?.endsWith(".scss")) {
|
||||
+ mod.importers.forEach((imp) => {
|
||||
+ update(getRelFile(imp.id));
|
||||
+ });
|
||||
+ }
|
||||
+ });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1882,7 +1920,7 @@ const pluginWebAccessibleResources = () => {
|
||||
if (contentScripts.size > 0) {
|
||||
const viteManifest = parseJsonAsset(
|
||||
bundle,
|
||||
- "manifest.json"
|
||||
+ ".vite/manifest.json"
|
||||
);
|
||||
const viteFiles = /* @__PURE__ */ new Map();
|
||||
for (const [, file] of Object.entries(viteManifest))
|
||||
diff --git a/package.json b/package.json
|
||||
index e0c47ae66ff399ad3a78abf38d8d93d1f038c55d..f84eb09ffbb5c41094935dd06e04ffe831e2d05a 100644
|
||||
--- a/package.json
|
||||
+++ b/package.json
|
||||
@@ -70,7 +70,7 @@
|
||||
"connect-injector": "^0.4.4",
|
||||
"convert-source-map": "^1.7.0",
|
||||
"debug": "^4.3.3",
|
||||
- "es-module-lexer": "^0.10.0",
|
||||
+ "es-module-lexer": "^1.4.1",
|
||||
"fast-glob": "^3.2.11",
|
||||
"fs-extra": "^10.0.1",
|
||||
"jsesc": "^3.0.2",
|
||||
50
patches/@unocss__vite.patch
Normal file
@@ -0,0 +1,50 @@
|
||||
diff --git a/dist/index.mjs b/dist/index.mjs
|
||||
index 7210f5fd650a0b7bb36b467fff85feb0d8e4ec63..c8f98bd314daec0b91c514ea9d9fc2b79cea8502 100644
|
||||
--- a/dist/index.mjs
|
||||
+++ b/dist/index.mjs
|
||||
@@ -369,15 +369,15 @@ const VIRTUAL_ENTRY_ALIAS = [
|
||||
/^(?:virtual:)?uno(?::(.+))?\.css(\?.*)?$/
|
||||
];
|
||||
const LAYER_MARK_ALL = "__ALL__";
|
||||
-const RESOLVED_ID_WITH_QUERY_RE = /[/\\]__uno(_.*?)?\.css(\?.*)?$/;
|
||||
-const RESOLVED_ID_RE = /[/\\]__uno(?:_(.*?))?\.css$/;
|
||||
+const RESOLVED_ID_WITH_QUERY_RE = /[/\\]uno(_.*?)?\.css(\?.*)?$/;
|
||||
+const RESOLVED_ID_RE = /[/\\]uno(?:_(.*?))?\.css$/;
|
||||
function resolveId(id) {
|
||||
if (id.match(RESOLVED_ID_WITH_QUERY_RE))
|
||||
return id;
|
||||
for (const alias of VIRTUAL_ENTRY_ALIAS) {
|
||||
const match = id.match(alias);
|
||||
if (match) {
|
||||
- return match[1] ? `/__uno_${match[1]}.css` : "/__uno.css";
|
||||
+ return match[1] ? `/uno_${match[1]}.css` : "/uno.css";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -652,7 +652,7 @@ function GlobalModeBuildPlugin(ctx) {
|
||||
css = await applyCssTransform(css, fakeCssId, options.dir, this);
|
||||
const transformHandler = "handler" in cssPost.transform ? cssPost.transform.handler : cssPost.transform;
|
||||
if (isLegacy) {
|
||||
- await transformHandler.call({}, css, "/__uno.css");
|
||||
+ await transformHandler.call({}, css, "/uno.css");
|
||||
} else {
|
||||
const hash = getHash(css);
|
||||
await transformHandler.call({}, getHashPlaceholder(hash), fakeCssId);
|
||||
@@ -914,7 +914,7 @@ function GlobalModeDevPlugin({ uno, tokens, tasks, flushTasks, affectedModules,
|
||||
const { hash, css } = await generateCSS(layer);
|
||||
return {
|
||||
// add hash to the chunk of CSS that it will send back to client to check if there is new CSS generated
|
||||
- code: `${css}__uno_hash_${hash}{--:'';}`,
|
||||
+ code: `${css}uno_hash_${hash}{--:'';}`,
|
||||
map: { mappings: "" }
|
||||
};
|
||||
},
|
||||
@@ -933,7 +933,7 @@ function GlobalModeDevPlugin({ uno, tokens, tasks, flushTasks, affectedModules,
|
||||
if (layer && code.includes("import.meta.hot")) {
|
||||
let hmr = `
|
||||
try {
|
||||
- let hash = __vite__css.match(/__uno_hash_(\\w{${HASH_LENGTH}})/)
|
||||
+ let hash = __vite__css.match(/uno_hash_(\\w{${HASH_LENGTH}})/)
|
||||
hash = hash && hash[1]
|
||||
if (!hash)
|
||||
console.warn('[unocss-hmr]', 'failed to get unocss hash, hmr might not work')
|
||||
14916
pnpm-lock.yaml
generated
Normal file
90
popup.html
@@ -1,90 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!-- This file is serving as the page for the browser action popup -->
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/popup.css">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="card" id="card-header" class='header_container'>
|
||||
<div id="buttons" class="header_buttons">
|
||||
<button id="clear" class="material_button header_button clear_button">Clear All</button>
|
||||
<button id="RIS" class="material_button header_button ris_button">Registrar Info </button>
|
||||
<button id="calendar" class="material_button header_button schedule_button">My Schedule</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul id="courseList" class='course_list'></ul>
|
||||
<h2 id="empty" class='empty_message'>
|
||||
<div id="main">Doesn't Look Like Anything To Me.</div>
|
||||
<span>(No Courses Saved)</span>
|
||||
</h2>
|
||||
<div class="settings_divider"></div>
|
||||
<input type="file" id="import_input" accept=".json" class="hide" />
|
||||
<div>
|
||||
<div id="meta-data" class="meta-container">
|
||||
<p class="meta"> <span class="meta-metric" id="meta-metric">17</span> hr</p>
|
||||
</div>
|
||||
<div class="settings">
|
||||
<button title='Search' class="settings_button search_button" id='search'>
|
||||
<i class="material-icons settings_icon">search</i>
|
||||
</button>
|
||||
<div id="search-popup" class="hide">
|
||||
<div class="flex-container">
|
||||
<div id='semcon' class="select-style item">
|
||||
<label>
|
||||
<select id="semesters"></select>
|
||||
</label>
|
||||
</div>
|
||||
<div id='depcon' class="select-style item">
|
||||
<label>
|
||||
<select id="department"></select>
|
||||
</label>
|
||||
</div>
|
||||
<div id='levcon' class="select-style item">
|
||||
<label>
|
||||
<select id="level">
|
||||
<option value="L">Lower</option>
|
||||
<option value="U">Upper</option>
|
||||
<option value="G">Grad</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<input class = "input-box" placeholder="Course # (optional)" type="text" id="courseCode"></input>
|
||||
</div>
|
||||
</div>
|
||||
<button id="search-class" class="material_button search-button">Search</button>
|
||||
</div>
|
||||
<button title='Import/Export' class="settings_button import_button" id='impexp'>
|
||||
<i class="material-icons settings_icon">import_export</i>
|
||||
</button>
|
||||
<div id="import-export-popup" class="hide">
|
||||
<div class="flex-container">
|
||||
<button id="import-class" class="simple-menu-option">
|
||||
<i class="material-icons">file_upload</i>Import Classes
|
||||
</button>
|
||||
<button id="export-class" class="simple-menu-option">
|
||||
<i class="material-icons">file_download</i>Export Classes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button title='Options' class="settings_button options_button" id='options_button'>
|
||||
<i class="material-icons settings_icon">settings</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/lib/jquery-3.3.1.min.js"></script>
|
||||
<script src="js/lib/moment.min.js"></script>
|
||||
<script src="js/Template.js"></script>
|
||||
<script src="js/config.js"></script>
|
||||
<script src="js/util.js"></script>
|
||||
<script src="js/popup.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
10
postcss.config.cjs
Normal file
@@ -0,0 +1,10 @@
|
||||
/* eslint-disable global-require */
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
cssnano: process.env.NODE_ENV !== 'development' ? {} : false,
|
||||
// '@unocss/postcss': {},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
BIN
public/database/grade_distributions.db
Normal file
BIN
public/fonts/inter-100.woff2
Normal file
BIN
public/fonts/inter-200.woff2
Normal file
BIN
public/fonts/inter-300.woff2
Normal file
BIN
public/fonts/inter-400.woff2
Normal file
BIN
public/fonts/inter-500.woff2
Normal file
BIN
public/fonts/inter-600.woff2
Normal file
BIN
public/fonts/inter-700.woff2
Normal file
BIN
public/fonts/inter-800.woff2
Normal file
BIN
public/fonts/inter-900.woff2
Normal file
BIN
public/fonts/roboto-flex.woff2
Normal file
BIN
public/fonts/roboto-mono.woff2
Normal file
30
public/icons/icon_beta.svg
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Beta" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
stroke-width: 70.06px;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
fill: #005f86;
|
||||
}
|
||||
|
||||
.cls-2, .cls-3 {
|
||||
stroke-width: 0px;
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
fill: #fff;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-2" width="1024" height="1024"/>
|
||||
<g>
|
||||
<circle class="cls-1" cx="512" cy="512" r="362"/>
|
||||
<rect class="cls-3" x="466.29" y="283.46" width="91.41" height="457.07"/>
|
||||
<rect class="cls-3" x="283.46" y="466.29" width="457.07" height="91.41"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 684 B |
BIN
public/icons/icon_beta_128.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |