Compare commits

...

178 Commits

Author SHA1 Message Date
Hykilpikonna d02cfe0557 [U] Release v0.3.4.561 2019-10-13 21:48:33 -04:00
Hykilpikonna aca0b5635b [+] Show error for assignments and grading too 2019-10-13 21:46:34 -04:00
Hykilpikonna 4e8d3aaeb9 [O] Fix line gap 2019-10-13 21:36:37 -04:00
Hykilpikonna 1c097b639a [O] Reverse dynamic font size 2019-10-13 21:36:28 -04:00
Hykilpikonna ed80b3c82b [O] Separate details and error details 2019-10-13 21:35:52 -04:00
Hykilpikonna 1a59e174ae [O] Make color class red (pink) 2019-10-13 21:31:21 -04:00
Hykilpikonna bbca7c2e14 [F] Should be class instead of style 2019-10-13 21:31:08 -04:00
Hykilpikonna 5c09490d5e [O] Dynamically add error class 2019-10-13 21:28:16 -04:00
Hykilpikonna ba9b24a276 [O] Encapsulate error message function 2019-10-13 21:28:04 -04:00
Hykilpikonna 755b61efe3 [O] Only show spinner if not error 2019-10-13 21:25:17 -04:00
Hykilpikonna 75d6d94757 [+] Switch title to 'Error' dynamically 2019-10-13 21:25:01 -04:00
Hykilpikonna a00285b38a [+] Bind loadingError variable 2019-10-13 21:23:32 -04:00
Hykilpikonna b529aa070a [O] Show error on http error too 2019-10-13 21:21:48 -04:00
Hykilpikonna 38d7b75831 [+] Encapsulate showError function 2019-10-13 21:20:45 -04:00
Hykilpikonna c3b81b5828 [+] Display error after course failed to load 2019-10-13 21:18:57 -04:00
Hykilpikonna 8aae753098 [+] Add loadingError field 2019-10-13 21:18:39 -04:00
Hykilpikonna 382a2aeabc [+] Add error property 2019-10-13 21:15:42 -04:00
Hykilpikonna ec056ef3b3 [+] Remove loading when it's done loading 2019-10-13 21:13:39 -04:00
Hykilpikonna 96d3e6b620 [O] Dynamically size entries based on index 2019-10-13 21:12:32 -04:00
Hykilpikonna 85f59a3983 [+] Add <br> every line 2019-10-13 21:07:50 -04:00
Hykilpikonna 71035ab87b [-] Remove unused pre css 2019-10-13 21:07:29 -04:00
Hykilpikonna bfd91af873 [O] Use span instead of pre 2019-10-13 21:07:17 -04:00
Hykilpikonna de5d406362 [O] Display loading line by line 2019-10-13 21:06:52 -04:00
Hykilpikonna 8c8f405aa5 [+] Add method to split loading messages 2019-10-13 21:03:58 -04:00
Hykilpikonna a59f2e6f7c [+] Log loading before checking grading 2019-10-13 21:02:46 -04:00
Hykilpikonna 5d06ee1c41 [+] Log loading before loading assignments 2019-10-13 21:02:38 -04:00
Hykilpikonna b818420df7 [+] Log loading before loading courses 2019-10-13 21:02:32 -04:00
Hykilpikonna dbe9c69771 [+] Log loading before login 2019-10-13 21:02:17 -04:00
Hykilpikonna 3a58699f62 [O] Fix <pre> tag font 2019-10-13 21:01:53 -04:00
Hykilpikonna f5804c3ce8 [O] Surround text with <pre> tag 2019-10-13 20:59:30 -04:00
Hykilpikonna 5ef7083ee6 [M] Move font-family to theme variable 2019-10-13 20:59:10 -04:00
Hykilpikonna 25370ec412 [+] Create function to log loading 2019-10-13 20:52:12 -04:00
Hykilpikonna b55c25aa7c [O] Hide loading on start because of the login screen 2019-10-13 20:48:17 -04:00
Hykilpikonna 9f68ac8377 [O] Only show loading when loading text is not empty 2019-10-13 20:46:46 -04:00
Hykilpikonna 335cde4d4e [+] Use actual loading text 2019-10-13 20:46:28 -04:00
Hykilpikonna 878b8cf87c [O] Inline loading script 2019-10-13 20:45:03 -04:00
Hykilpikonna 283904d976 [O] Align loading message to bottom 2019-10-13 20:43:52 -04:00
Hykilpikonna 11dea5182b [O] Make details color darker 2019-10-13 20:39:45 -04:00
Hykilpikonna 87f8f49c39 [O] Correct spinner alignments 2019-10-13 20:38:44 -04:00
Hykilpikonna 595033b80f [O] Make the stroke white 2019-10-13 20:37:21 -04:00
Hykilpikonna ccd32ed7e6 [+] Add a loading spinner 2019-10-13 20:35:53 -04:00
Hykilpikonna a40e3b24eb [O] Make details font size smaller 2019-10-13 20:35:41 -04:00
Hykilpikonna 6a4ff9b0a7 [O] Make title font size bigger 2019-10-13 20:35:27 -04:00
Hykilpikonna 2dfb0bf447 [+] Add loading title 2019-10-13 20:35:16 -04:00
Hykilpikonna 21e6352ace Revert "[-] Remove loading"
This reverts commit f1089dbdf5.
2019-10-13 20:29:45 -04:00
Hykilpikonna f1089dbdf5 [-] Remove loading 2019-10-13 20:29:02 -04:00
Hykilpikonna e95efbff59 [O] Center text box vertically 2019-10-13 20:00:10 -04:00
Hykilpikonna 92b46baeed [O] Center text horizontally 2019-10-13 19:59:59 -04:00
Hykilpikonna d45fce6506 [+] Add a loading component in html for testing 2019-10-13 19:43:30 -04:00
Hykilpikonna e4374a6731 [+] Add loading to app 2019-10-13 19:43:11 -04:00
Hykilpikonna cd402c4b86 [O] Make text color white 2019-10-13 19:42:56 -04:00
Hykilpikonna 25bf445582 [O] Darken loading background 2019-10-13 19:42:47 -04:00
Hykilpikonna 74287289e0 [O] Center loading screen 2019-10-13 19:42:33 -04:00
Hykilpikonna cc23f8565a [+] Create loading overlay 2019-10-13 19:42:17 -04:00
Hykilpikonna a537ced0d7 [O] Optimize isAssignmentsReady() 2019-10-13 19:11:38 -04:00
Hykilpikonna 797d962e40 [O] Optimize isGradingReady() with Array.every() 2019-10-13 19:09:55 -04:00
Hykilpikonna 992be72d8d [+] Create course page 2019-10-13 18:56:06 -04:00
Hykilpikonna 375712c0a8 [F] Fix logic error 2019-10-13 18:32:24 -04:00
Hykilpikonna 0b7ab5923c [+] Add version control to cookies 2019-10-13 18:23:36 -04:00
Hykilpikonna d077818508 [F] Make corrections after reverts 2019-10-13 18:23:25 -04:00
Hykilpikonna c991b75384 [-] Revert "[+] Save username to cookies on login"
This reverts commit 5441592d68.
2019-10-13 18:03:18 -04:00
Hykilpikonna 9f59f517b5 [-] Revert "[+] Return username with token"
This reverts commit e28f68aae3.
2019-10-13 18:03:05 -04:00
Hykilpikonna 6654f78486 [-] Revert "[+] Create token interface"
This reverts commit 353a623e5f.
2019-10-13 18:02:45 -04:00
Hykilpikonna 206fef682f [-] Revert "[U] Update http-utils to use token.token"
This reverts commit 543b0ddefe.
2019-10-13 18:02:12 -04:00
Hykilpikonna 3e454423a1 [-] Revert "[U] Also include username when posting request"
This reverts commit 6607afc898.
2019-10-13 18:02:00 -04:00
Hykilpikonna 8326a9e923 [-] Revert "[U] Update variable types"
This reverts commit 6d191f04fb.
2019-10-13 18:01:46 -04:00
Hykilpikonna 5013830815 [-] Revert "[F] Fix http-utils constructor type error"
This reverts commit 0f93a3581f.
2019-10-13 18:00:56 -04:00
Hykilpikonna e4ba53f460 [-] Revert "[O] Optimize token storage"
This reverts commit 846f26db75.
2019-10-13 17:59:07 -04:00
Hykilpikonna fabdc10467 [-] Revert "[U] Use response.data.courses for courses"
This reverts commit 8caab70b25.
2019-10-13 17:57:39 -04:00
Hykilpikonna 91488c6a9f [-] Revert "[+] Save csrf token"
This reverts commit d4df0c3562.
2019-10-13 17:39:25 -04:00
Hykilpikonna f346364633 [O] Make value.min exactly the min value 2019-10-13 17:35:32 -04:00
Hykilpikonna 34e482e8a9 [+] Define value.max for line chart 2019-10-13 17:35:16 -04:00
Hykilpikonna 9aaf662a60 [F] Use scoreId instead of assignmentId when requesting 2019-10-13 15:27:02 -04:00
Hykilpikonna 0b65ebbb00 [+] Parse score_id when parsing 2019-10-13 15:26:32 -04:00
Hykilpikonna 74d1c88f82 [+] Add scoreId to Assignment model 2019-10-13 15:26:22 -04:00
Hykilpikonna 70c8375810 [+] Listen mark as read event 2019-10-13 15:21:00 -04:00
Hykilpikonna b554128337 [+] Implement mark assignment as read 2019-10-13 15:20:49 -04:00
Hykilpikonna 4a8ce2ca18 [O] Use App.http instead of this.http 2019-10-13 15:12:00 -04:00
Hykilpikonna a2df22c1da [O] Make http client static 2019-10-13 15:07:07 -04:00
Hykilpikonna 047ceda252 [-] Remove unnecessary unreadTable() function 2019-10-13 14:53:00 -04:00
Hykilpikonna c94435360f [O] Adjust expansion background clor 2019-10-13 14:51:47 -04:00
Hykilpikonna ed0b7a9740 [O] Use @click instead of onclick 2019-10-13 14:49:44 -04:00
Hykilpikonna b168c4bb82 [+] Call mark as read on click 2019-10-13 14:48:28 -04:00
Hykilpikonna 5078011f40 [+] Add markAsRead() function 2019-10-13 14:47:56 -04:00
Hykilpikonna 1428953cb7 [O] Remove button borders 2019-10-13 14:43:54 -04:00
Hykilpikonna 7f962704d2 [O] Make button paddings smaller 2019-10-13 14:43:44 -04:00
Hykilpikonna 2970263db5 [O] Add left margin 2019-10-13 14:43:31 -04:00
Hykilpikonna 91d9fb90ac [O] Remove button background 2019-10-13 14:43:22 -04:00
Hykilpikonna adb28089b9 [O] Make the button's size mini 2019-10-13 14:42:49 -04:00
Hykilpikonna 6f4a012ac4 [O] Use button instead 2019-10-13 14:42:29 -04:00
Hykilpikonna b807a41496 [O] Make background lighter 2019-10-13 14:08:29 -04:00
Hykilpikonna 02f1fb797f [O] Set color for mark as read 2019-10-13 14:07:54 -04:00
Hykilpikonna caee9117b3 [O] Adjust padding 2019-10-13 14:07:45 -04:00
Hykilpikonna 48cec4c0f0 [+] Add mark-as-read span 2019-10-13 14:07:33 -04:00
Hykilpikonna d4df0c3562 [+] Save csrf token 2019-10-12 20:36:55 -04:00
Hykilpikonna 8caab70b25 [U] Use response.data.courses for courses 2019-10-12 20:36:22 -04:00
Hykilpikonna 846f26db75 [O] Optimize token storage 2019-10-12 20:35:59 -04:00
Hykilpikonna ea2bdb226d [U] Update key names 2019-10-12 20:19:09 -04:00
Hykilpikonna 0f93a3581f [F] Fix http-utils constructor type error 2019-10-12 20:17:00 -04:00
Hykilpikonna 6607afc898 [U] Also include username when posting request 2019-10-12 20:14:57 -04:00
Hykilpikonna 543b0ddefe [U] Update http-utils to use token.token 2019-10-12 20:14:33 -04:00
Hykilpikonna 6d191f04fb [U] Update variable types 2019-10-12 20:14:08 -04:00
Hykilpikonna 353a623e5f [+] Create token interface 2019-10-12 20:11:56 -04:00
Hykilpikonna e28f68aae3 [+] Return username with token 2019-10-12 20:09:22 -04:00
Hykilpikonna 5441592d68 [+] Save username to cookies on login 2019-10-12 20:09:04 -04:00
Hykilpikonna a8e96b142d [+] Add google analytics tag 2019-10-07 21:31:46 -04:00
Hykilpikonna 4527b58084 [O] Optimize alignment for small screens 2019-10-05 20:36:00 -04:00
Hykilpikonna 80d14c1400 [O] Limit max width 2019-10-05 20:30:00 -04:00
Hykilpikonna 86ed26afeb [U] Pre-release v0.3.2.452 2019-10-05 20:15:30 -04:00
Hykilpikonna 35c4147cc1 [O] Lighten drop shadow 2019-10-05 20:13:06 -04:00
Hykilpikonna 711e69ddfb [O] Make font color darker 2019-10-05 20:07:26 -04:00
Hykilpikonna 90d9cac19a [+] Add dynamic assignment type coloring 2019-10-05 20:07:10 -04:00
Hykilpikonna 61593d7d23 [O] Adjust el-col width 2019-10-05 20:02:11 -04:00
Hykilpikonna 7c41e7adcc [O] Add right margins 2019-10-05 20:02:00 -04:00
Hykilpikonna 0215be8681 [O] Make days from now font smaller 2019-10-05 20:01:46 -04:00
Hykilpikonna 1139384ab3 [O] Make assignment type looks like Veracross 2019-10-05 19:57:40 -04:00
Hykilpikonna 45174422e9 [+] Add days from now 2019-10-05 19:57:18 -04:00
Hykilpikonna 2077d784fd [O] Make formatDate return moment instead 2019-10-05 19:55:41 -04:00
Hykilpikonna fa341101a8 [+] Add assignment color variables 2019-10-05 19:47:15 -04:00
Hykilpikonna 1959ac589d [O] show entry box for assignment type 2019-10-05 19:43:46 -04:00
Hykilpikonna 5744493ac3 [+] Add padding to first child 2019-10-05 19:43:06 -04:00
Hykilpikonna 64eb4530af [O] Only show top shadow for first child 2019-10-05 19:22:44 -04:00
Hykilpikonna d38fdfaced [O] Brighten percent score emphesis 2019-10-05 19:20:53 -04:00
Hykilpikonna f76484f824 [O] Adjust el-col width 2019-10-05 19:20:35 -04:00
Hykilpikonna ef6adb0a27 [O] Add entry-box class to span tags 2019-10-05 19:20:22 -04:00
Hykilpikonna ca80df9541 [O] Separate span box class 2019-10-05 19:19:41 -04:00
Hykilpikonna 828907120b [O] Add top shadow 2019-10-05 19:18:43 -04:00
Hykilpikonna 460074b18a [O] Adjust background color 2019-10-05 19:17:00 -04:00
Hykilpikonna 104bd4498e [+] Emphasize percentage score 2019-10-05 17:19:30 -04:00
Hykilpikonna 97082b1e55 [O] Separate percent symbol into new span 2019-10-05 17:18:58 -04:00
Hykilpikonna c9561fba71 [F] Fix "v-for should have explicit keys" 2019-10-05 17:12:31 -04:00
Hykilpikonna 8aa913fe09 [+] Display score in percentage 2019-10-05 17:08:55 -04:00
Hykilpikonna a598521491 [O] Emphasise current score 2019-10-05 17:06:24 -04:00
Hykilpikonna 6461456c16 [O] Style span box to look the same as Veracross 2019-10-05 17:04:35 -04:00
Hykilpikonna b4f697bdea [O] Add css selector classes to spans 2019-10-05 17:01:50 -04:00
Hykilpikonna 721295b9d1 [+] Separate <span>s 2019-10-05 17:00:47 -04:00
Hykilpikonna 70c6e74623 [O] Align grade to the right 2019-10-05 16:59:30 -04:00
Hykilpikonna 1348ca27ab [O] Align text left 2019-10-05 16:58:55 -04:00
Hykilpikonna 116592e436 [+] Add css selector classes to cols 2019-10-05 16:56:31 -04:00
Hykilpikonna 19284a4ddf [O] Combine type and description cols 2019-10-05 16:55:05 -04:00
Hykilpikonna 35e603b850 Revert "[-] Remove el-row and el-col"
This reverts commit 882c7bb35e.
2019-10-05 16:54:19 -04:00
Hykilpikonna 882c7bb35e [-] Remove el-row and el-col 2019-10-05 16:53:51 -04:00
Hykilpikonna 9c8ce3a7f2 [O] Display formatted date 2019-10-05 16:50:49 -04:00
Hykilpikonna 8a6af65786 [+] Create method to format date with moment 2019-10-05 16:50:32 -04:00
Hykilpikonna 4633bd902c [+] Install moment dependency 2019-10-05 16:35:47 -04:00
Hykilpikonna 10fcb8a2f6 [O] Add padding 2019-10-05 16:29:10 -04:00
Hykilpikonna 3ad47eddfd [O] Adjust col width 2019-10-05 16:28:58 -04:00
Hykilpikonna 636f1474bd [O] Vertically center row content 2019-10-05 16:28:48 -04:00
Hykilpikonna ebc9fac4dc [+] Make unread row higher 2019-10-05 16:28:32 -04:00
Hykilpikonna a0e5db6ed9 [+] Parse typeId in jsonUtils 2019-10-05 16:26:19 -04:00
Hykilpikonna f8acd8e222 [+] Add typeId to Assignment model 2019-10-05 16:26:02 -04:00
Hykilpikonna 7b21f82024 [+] Create a table 2019-10-05 16:19:17 -04:00
Hykilpikonna 240cd7ce69 [+] Use unreadEntry components 2019-10-05 16:14:55 -04:00
Hykilpikonna 8a4f9c6f79 [+] Import UnreadEntry component 2019-10-05 16:14:42 -04:00
Hykilpikonna 16f5865c4c [O] Also cache unread assignments 2019-10-05 16:14:31 -04:00
Hykilpikonna 25c3d8e6c1 [+] Create unread-entry component 2019-10-05 16:10:18 -04:00
Hykilpikonna e1584c80a5 [+] Add demo unread entry 2019-10-05 16:05:39 -04:00
Hykilpikonna 89dc493edf [+] Use el-table but comment out 2019-10-05 16:05:14 -04:00
Hykilpikonna aa59075939 [+] Only display expantion when unread messages != 0 2019-10-05 15:50:44 -04:00
Hykilpikonna c55beaf30d [-] Remove debug height declaration 2019-10-05 15:49:27 -04:00
Hykilpikonna 67f1343744 [-] Remove duplicate vertical center code 2019-10-05 15:43:17 -04:00
Hykilpikonna 6b0e0fc8e8 [U] Vertical center main cards 2019-10-05 15:42:38 -04:00
Hykilpikonna af41ad5f53 [O] Separate vertical centering css selector 2019-10-05 15:42:06 -04:00
Hykilpikonna 622cd524e5 [O] Make size larger for debug 2019-10-05 15:41:52 -04:00
Hykilpikonna 7266cf0d80 [+] Make content background darker 2019-10-05 15:39:44 -04:00
Hykilpikonna 47fc11ed96 [+] Add custom padding to content 2019-10-05 15:39:32 -04:00
Hykilpikonna fd927991c7 [F] Remove card padding for styling issues 2019-10-05 15:37:44 -04:00
Hykilpikonna 4b5e6d9856 [+] Add 'main' css class to avoid conflict 2019-10-05 15:32:07 -04:00
Hykilpikonna 3aa5ef9c95 [+] Add notfication div 2019-10-05 15:31:27 -04:00
Hykilpikonna ded76b774c [O] Vertically center content 2019-10-05 15:30:04 -04:00
Hykilpikonna 1bcf2f7410 [O] Make the content hight constant 2019-10-05 15:29:50 -04:00
Hykilpikonna d8cce9ae11 [O] Expand the max hight 2019-10-05 15:29:22 -04:00
Hykilpikonna b4f29559cf [F] Remove global declaration of height 2019-10-05 15:28:08 -04:00
Hykilpikonna a7ea833860 [O] Wrap content in div instead 2019-10-05 15:20:50 -04:00
Hykilpikonna 9c54033343 [+] Wrap course-card around a parent card 2019-10-05 15:11:18 -04:00
Hykilpikonna 7b9dab9d78 [F] Fix rounding issue when detecting necessity of grading api 2019-10-05 14:34:47 -04:00
Hykilpikonna 7f094cbafb [F] Fix typo: should be 'TOTAL_MEAN' instead of 'TOTAL_AVERAGE' 2019-10-05 14:31:08 -04:00
Hykilpikonna c4b8542b5b [F] Skip courses without graded assignments instead of without any assignments 2019-10-05 14:27:18 -04:00
24 changed files with 527 additions and 112 deletions
+5
View File
@@ -6935,6 +6935,11 @@
}
}
},
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/move-concurrently/download/move-concurrently-1.0.1.tgz",
+1
View File
@@ -11,6 +11,7 @@
"core-js": "^2.6.5",
"echarts": "^4.2.1",
"element-ui": "^2.11.1",
"moment": "^2.24.0",
"p-wait-for": "^3.1.0",
"v-charts": "^1.19.0",
"vue": "^2.6.10",
+10
View File
@@ -25,4 +25,14 @@
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Q615K1KFLC"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-Q615K1KFLC');
</script>
</html>
+15 -1
View File
@@ -1,14 +1,28 @@
#app
{
font-family: 'Avenir', Helvetica, Arial, sans-serif;
font-family: var(--font);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#app-content
{
// Limit max width
max-width: 1300px;
text-align: center;
margin: auto;
}
.theme-default
{
--unread: #ff6c00;
--main: #0c6dad;
--assignment-type-2: #3f991e;
--assignment-type-3: #ff9900;
--assignment-type-4: #b02b02;
--font: 'Avenir', Helvetica, Arial, sans-serif;
}
+57 -56
View File
@@ -8,6 +8,7 @@ import pWaitFor from 'p-wait-for';
import {HttpUtils} from '@/utils/http-utils';
import {CourseUtils} from '@/utils/course-utils';
import {GPAUtils} from '@/utils/gpa-utils';
import Loading from '@/components/loading/loading.vue';
/**
* Objects of this interface represent assignment grades.
@@ -15,7 +16,9 @@ import {GPAUtils} from '@/utils/gpa-utils';
export interface Assignment
{
id: number,
scoreId: number,
type: string,
typeId: number,
description: string,
date: string,
complete: string,
@@ -55,7 +58,7 @@ export interface Course
}
@Component({
components: {Login, Navigation, Overall},
components: {Login, Navigation, Overall, Loading},
})
export default class App extends Vue
{
@@ -77,8 +80,14 @@ export default class App extends Vue
// Token
public token: string = '';
// Loading text
public loading: string = '';
// Loading error
public loadingError: boolean = false;
// Http Client
public http: HttpUtils = new HttpUtils('');
public static http: HttpUtils = new HttpUtils();
/**
* This is called when the instance is created.
@@ -99,11 +108,14 @@ export default class App extends Vue
// Hide login bar
this.showLogin = false;
// Show loading message
this.logLoading('1. Logging in...');
// Store token
this.token = token;
// Assign token to http client
this.http.token = token;
App.http.token = token;
// Load data
this.loadCoursesAfterLogin();
@@ -114,7 +126,11 @@ export default class App extends Vue
*/
public loadCoursesAfterLogin()
{
this.http.post('/courses', {}).then(response =>
// Show loading message
this.logLoading('2. Loading courses...');
// Post request
App.http.post('/courses', {}).then(response =>
{
// Check success
if (response.success)
@@ -125,13 +141,9 @@ export default class App extends Vue
// Load assignments
this.loadAssignments();
}
else
{
// Show error message TODO: Show it properly
alert(response.data);
}
else throw new Error(response.data);
})
.catch(alert);
.catch(e => this.showError(`Error: Course data failed to load.\n(${e})`));
}
/**
@@ -139,11 +151,14 @@ export default class App extends Vue
*/
public loadAssignments()
{
// Show loading message
this.logLoading('3. Loading assignments...');
// Get assignments for all the courses
this.courses.forEach(course =>
{
// Send request to get assignments
this.http.post('/assignments', {id: course.assignmentsId}).then(response =>
App.http.post('/assignments', {'assignmentsId': course.assignmentsId}).then(response =>
{
// Check success
if (response.success)
@@ -152,17 +167,13 @@ export default class App extends Vue
// Parse json and filter it
course.assignments = JsonUtils.filterAssignments(response.data);
}
else
{
// Show error message TODO: Show it properly
alert(response.data);
}
else throw new Error(response.data);
})
.catch(alert);
.catch(e => this.showError(`Error: Assignments data failed to load.\n(${e})`));
});
// Wait for assignments to be ready.
pWaitFor(() => this.isAssignmentsReady()).then(() =>
pWaitFor(() => this.courses.every(c => c.assignments != null)).then(() =>
{
// Filter courses
this.filteredCourses = CourseUtils.getGradedCourses(this.courses);
@@ -173,37 +184,25 @@ export default class App extends Vue
}
/**
* Are assignments ready or not
*
* @returns boolean Ready or not
*/
private isAssignmentsReady(): boolean
{
for (const course of this.courses)
{
if (course.assignments == null) return false;
}
return true;
}
/**
* Check the courses' grading algorithms. (Total-average or percent-type)
* Check the courses' grading algorithms. (Total-mean or percent-type)
*/
private checkGradingAlgorithms()
{
// Show loading message
this.logLoading('4. Checking grading algorithms...');
// Loop through all the courses
for (const course of this.filteredCourses)
{
// Check if total-average grade is the same with percent-type grade
if (course.numericGrade == GPAUtils.getTotalMeanAverage(course))
if (course.numericGrade == +GPAUtils.getTotalMeanAverage(course).toFixed(2))
{
course.grading = {method: 'TOTAL_AVERAGE', weightingMap: {}};
course.grading = {method: 'TOTAL_MEAN', weightingMap: {}};
}
else
{
// Request grading scheme for this course
this.http.post('/grading', {'assignment_id': course.assignmentsId}).then(response =>
App.http.post('/grading', {'assignmentsId': course.assignmentsId}).then(response =>
{
// Check success
if (response.success)
@@ -211,41 +210,43 @@ export default class App extends Vue
// Add it to course
course.grading = response.data;
}
else
{
// Show error message TODO: Show it properly
alert(response.data)
}
else throw new Error(response.data);
})
.catch(alert)
.catch(e => this.showError(`Error: Grading data failed to load.\n(${e})`))
}
}
// Wait for done
pWaitFor(() => this.isGradingReady()).then(() =>
pWaitFor(() => this.filteredCourses.every(c => c.grading != undefined)).then(() =>
{
// When the assignments are ready
// TODO: Display loading
this.assignmentsReady = true;
// Remove loading
this.logLoading('');
})
}
/**
* Are grading algorithms ready or not.
* Log a message to loading screen
*
* @returns boolean Ready or not
* @param message Message
*/
private isGradingReady(): boolean
private logLoading(message: string)
{
for (const course of this.filteredCourses)
{
if (course.grading == undefined)
{
return false;
}
}
if (message == '') this.loading = '';
else this.loading += '\n' + message;
}
return true;
/**
* Show error message on loading screen
*
* @param message Error message
*/
private showError(message: string)
{
this.loadingError = true;
this.loading = message;
}
/**
+3 -1
View File
@@ -1,6 +1,6 @@
<template>
<div id="app" class="theme-default">
<login v-if="showLogin" v-on:login:token="onLogin" :http="http"></login>
<login v-if="showLogin" v-on:login:token="onLogin"></login>
<navigation :courses="filteredCourses"
v-on:sign-out="signOut()"
v-on:navigation:select="onNavigate">
@@ -11,6 +11,8 @@
v-if="selectedTab === 'overall' && assignmentsReady">
</overall>
</div>
<loading v-if="loading !== ''" :text="loading" :error="loadingError"></loading>
</div>
</template>
+115
View File
@@ -0,0 +1,115 @@
<template>
<div id="loading">
<div id="text" :class="message()">
{{message()}}
<div v-if="!error" class="el-loading-spinner">
<svg viewBox="25 25 50 50" class="circular">
<circle cx="50" cy="50" r="20" fill="none" class="path" />
</svg>
</div>
<div v-if="error" id="error-details">
<span v-for="(line, index) in getText()" :style="`font-size: ${-index === 0 ? 16 : 12}px;`">
{{line}}
<br>
</span>
</div>
</div>
<div v-if="!error" id="details">
<span v-for="(line, index) in getText()" :style="`font-size: ${16 - getText().length + index}px;`">
{{line}}
<br>
</span>
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
@Component({
components: {}
})
export default class Loading extends Vue
{
// @ts-ignore
@Prop() text: string;
// @ts-ignore
@Prop() error: boolean;
getText()
{
return this.text.split('\n');
}
message()
{
return this.error ? 'Error' : 'Loading';
}
}
</script>
<style scoped>
#loading
{
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background: #00000065;
text-align: center;
}
.Error
{
color: #ffdddd !important;
}
#text
{
color: white;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 46px;
}
#details
{
width: 100%;
position: absolute;
bottom: 0;
left: 0;
margin-top: -5px;
font-size: 16px;
color: #eeeeee;
}
#error-details
{
font-size: 16px;
}
.el-loading-spinner
{
top: unset !important;
margin-top: 0 !important;
width: unset !important;
position: unset !important;
}
.el-loading-spinner .path
{
stroke: white;
}
</style>
+10 -4
View File
@@ -1,6 +1,7 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Constants from '@/constants';
import {HttpUtils} from '@/utils/http-utils';
import App from '@/components/app/app';
/**
* This component handles user login, and obtains data from the server.
@@ -17,14 +18,18 @@ export default class Login extends Vue
public loading: boolean = false;
public error: String = '';
@Prop()
public http?: HttpUtils;
/**
* This is called when the instance is created.
*/
public created()
{
// Check cookies version
if (!this.$cookies.isKey('va.version') || this.$cookies.get('va.version') != Constants.VERSION)
{
// Clear all cookies
this.$cookies.keys().forEach(key => this.$cookies.remove(key));
}
// Check login cookies
if (this.$cookies.isKey('va.token'))
{
@@ -42,7 +47,7 @@ export default class Login extends Vue
this.loading = true;
// Fetch request
(<HttpUtils> this.http).post('/login', {username: this.username, password: this.password})
App.http.post('/login', {username: this.username, password: this.password})
.then(response =>
{
// Check success
@@ -50,6 +55,7 @@ export default class Login extends Vue
{
// Save token to cookies
this.$cookies.set('va.token', response.data, '7d');
this.$cookies.set('va.version', Constants.VERSION);
// Call custom event with token
this.$emit('login:token', response.data);
+1 -1
View File
@@ -8,7 +8,7 @@ export default class Constants
*/
public static API_URL: string = 'https://va.hydev.org/api';
public static VERSION: string = '0.3.1.382';
public static VERSION: string = '0.3.4.561';
public static GITHUB: string = 'https://github.com/HyDevelop/VeracrossAnalyzer.Client';
View File
+15
View File
@@ -0,0 +1,15 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import OverallLine from '@/pages/overall/overall-line/overall-line';
import OverallBar from '@/pages/overall/overall-bar/overall-bar';
import OverallCourse from '@/pages/overall/overall-course/overall-course';
import {Course} from '@/components/app/app';
import {GPAUtils} from '@/utils/gpa-utils';
@Component({
components: {OverallLine, OverallBar, OverallCourse}
})
export default class CoursePage extends Vue
{
// @ts-ignore
@Prop({required: true}) course: Course;
}
+7
View File
@@ -0,0 +1,7 @@
<template>
<div id="course-page">
</div>
</template>
<script src="./course-page.ts" lang="ts"></script>
<style src="./course-page.scss" lang="scss"></style>
@@ -6,10 +6,36 @@
margin-left: 20px;
// Height limit
max-height: 90px;
max-height: 250px;
// Limit name length
white-space: nowrap;
// Expansion color
background: #f4f6f9;
// Main card content
.course-card-content.main
{
padding: 0 20px 0 20px;
height: 90px;
// Main color
background: white;
}
// Expansion content
.course-card-content.expand.notification
{
}
}
// Remove card padding for styling issues
div.el-card.course-card > div.el-card__body
{
padding-right: 0 !important;
padding-left: 0 !important;
}
.course-col-name
@@ -1,9 +1,11 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Course} from '@/components/app/app';
import App, {Assignment, Course} from '@/components/app/app';
import {GPAUtils} from '@/utils/gpa-utils';
import Constants from '@/constants';
import UnreadEntry from '@/pages/overall/overall-course/unread-entry/unread-entry';
@Component({
components: {UnreadEntry}
})
export default class OverallCourse extends Vue
{
@@ -11,6 +13,7 @@ export default class OverallCourse extends Vue
@Prop({required: true}) course: Course;
private unread: number = -1;
private unreadAssignments: Assignment[] = [];
/**
* Count the number of unread assignments with cache
@@ -19,8 +22,31 @@ export default class OverallCourse extends Vue
{
if (this.unread == -1)
{
return this.unread = this.course.assignments.filter(a => a.unread).length;
this.unreadAssignments = this.course.assignments.filter(a => a.unread);
return this.unread = this.unreadAssignments.length;
}
else return this.unread;
}
/**
* Mark an assignment as read
*/
markAsRead(assignment: Assignment)
{
App.http.post('/mark-as-read', {scoreId: assignment.scoreId})
.then(response =>
{
// Check success
if (response.success)
{
this.unreadAssignments = this.unreadAssignments.filter(a => a != assignment);
this.unread = this.unreadAssignments.length;
}
else
{
// Show error message TODO: Show it properly
alert(response.data)
}
})
}
}
@@ -1,34 +1,44 @@
<template>
<div id="overall-course">
<el-card class="course-card">
<el-row>
<el-col :span="6" class="course-col-name">
<div class="course-name">
{{course.name}}
</div>
<div class="course-teacher">
{{course.teacherName}}
</div>
</el-col>
<el-col :span="12">
&nbsp;
</el-col>
<el-col :span="6" class="course-col-grade">
<div class="course-grade">
<span class="letter">{{course.letterGrade}} </span>
<span class="numeric">{{course.numericGrade.toFixed(2)}}</span>
<span class="percent">%</span>
</div>
<div class="course-updates" :class="countUnread() === 0 ? 'none' : 'unread'">
<span class="unread-number">
{{countUnread()}}
</span>
<span class="unread-text">
new update{{countUnread() >= 2 ? 's' : ''}}
</span>
</div>
</el-col>
</el-row>
<div class="course-card-content main vertical-center">
<el-row>
<el-col :span="6" class="course-col-name">
<div class="course-name">
{{course.name}}
</div>
<div class="course-teacher">
{{course.teacherName}}
</div>
</el-col>
<el-col :span="12">
&nbsp;
</el-col>
<el-col :span="6" class="course-col-grade">
<div class="course-grade">
<span class="letter">{{course.letterGrade}} </span>
<span class="numeric">{{course.numericGrade.toFixed(2)}}</span>
<span class="percent">%</span>
</div>
<div class="course-updates" :class="countUnread() === 0 ? 'none' : 'unread'">
<span class="unread-number">
{{countUnread()}}
</span>
<span class="unread-text">
new update{{countUnread() >= 2 ? 's' : ''}}
</span>
</div>
</el-col>
</el-row>
</div>
<div class="course-card-content expand notification"
v-if="countUnread() !== 0">
<unread-entry v-for="assignment in unreadAssignments"
:assignment="assignment"
:key="assignment.id"
v-on:mark-as-read="markAsRead">
</unread-entry>
</div>
</el-card>
</div>
</template>
@@ -0,0 +1,107 @@
// Row
.unread-entry
{
height: 40px;
padding: 0 10px 0 20px;
background: #f5f7fa;
text-align: left;
// Date
.el-col.date
{
min-width: 130px;
span.month
{
margin-right: 5px;
}
span.now
{
font-size: 11px;
color: #888;
}
}
// Description
.el-col.description
{
width: unset;
span.type
{
display: inline-block;
font-size: 13px;
font-weight: 700;
background: #eee;
border-left: 2px solid #000;
height: 22px;
line-height: 22px;
margin-right: 8px;
}
}
// Grade
.el-col.grade
{
text-align: right;
float: right;
span.percent
{
font-style: italic;
background: #ffc;
color: #555;
margin-right: 8px;
.symbol
{
padding: 0 1px;
}
}
// Score you got
span.score
{
background: #f2f2f2;
color: #555;
}
// Max score
span.max
{
background: #ddd;
color: #333;
}
// Mark as read
button.mark-as-read
{
margin-left: 8px;
color: #aaa;
padding: 4px;
}
}
.entry-box
{
height: 22px;
padding: 0 5px;
}
}
.unread-entry:first-child
{
padding-top: 3px;
// Top shadow
// https://stackoverflow.com/questions/17572619/inset-box-shadow-only-on-one-side
box-shadow: inset 0 7px 9px -7px rgba(0,0,0,0.1);
}
@@ -0,0 +1,30 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Assignment, Course} from '@/components/app/app';
import moment from 'moment';
@Component({
})
export default class UnreadEntry extends Vue
{
// @ts-ignore
@Prop({required: true}) assignment: Assignment;
/**
* Format a date to the displayed format
*
* @param date Date
*/
getMoment(date: string)
{
return moment(new Date(date));
}
/**
* Mark this unread assignment as read
*/
markAsRead()
{
// Call custom event
this.$emit('mark-as-read', this.assignment)
}
}
@@ -0,0 +1,31 @@
<template>
<div class="unread-entry vertical-center">
<el-row class="unread-row">
<el-col :span="3" class="date">
<span class="month">{{getMoment(assignment.date).format("MMM Do")}}</span>
<span class="now">({{getMoment(assignment.date).fromNow()}})</span>
</el-col>
<el-col :span="15" class="description">
<span class="type entry-box"
:style="`border-color: var(--assignment-type-${assignment.typeId})`">
{{assignment.type}}
</span>
<span class="text">{{assignment.description}}</span>
</el-col>
<el-col :span="6" class="grade">
<span class="percent entry-box">
{{(assignment.score / assignment.scoreMax * 100).toFixed(1)}}
<span class="symbol">%</span>
</span>
<span class="score entry-box">{{assignment.score}}</span>
<span class="max entry-box">{{assignment.scoreMax}}</span>
<el-button class="mark-as-read" size="mini" type="text"
icon="el-icon-close" @click="markAsRead">
</el-button>
</el-col>
</el-row>
</div>
</template>
<script src="./unread-entry.ts" lang="ts"></script>
<style src="./unread-entry.scss" lang="scss"></style>
@@ -56,7 +56,8 @@ export default class OverallLine extends Vue
},
yAxis:
{
min: (value: any) => value.min - 10
min: (value: any) => value.min,
max: (value: any) => value.max
}
};
+14 -6
View File
@@ -3,13 +3,12 @@
.el-card
{
margin: 10px;
height: 494px;
padding: 0;
}
// Vertical center
display: flex;
justify-content: center;
flex-direction: column;
.el-card.large
{
height: 494px;
}
.gpa-card
@@ -31,7 +30,7 @@
.gpa.text
{
font-size: 35px;
font-family: 'Avenir', Helvetica, Arial, sans-serif;
font-family: var(--font);
}
.gpa.max
@@ -60,3 +59,12 @@
padding-top: 0 !important;
padding-bottom: 0 !important;
}
// Vertical centering
.vertical-center
{
// Vertical center
display: flex;
justify-content: center;
flex-direction: column;
}
+7 -4
View File
@@ -2,7 +2,7 @@
<div id="overall">
<el-row>
<el-col :span="4">
<el-card class="gpa-card">
<el-card class="large gpa-card vertical-center">
<div style="padding: 14px;">
<span class="gpa header">GPA:</span>
<span class="gpa text">{{getGPA().gpa}}</span>
@@ -14,18 +14,21 @@
</el-card>
</el-col>
<el-col :span="14">
<el-card class="overall-line-card">
<el-card class="large overall-line-card vertical-center">
<overall-line :courses="courses"></overall-line>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="overall-bar-card">
<el-card class="large overall-bar-card vertical-center">
<overall-bar :courses="courses"></overall-bar>
</el-card>
</el-col>
</el-row>
<overall-course v-for="course in courses" :course="course"></overall-course>
<overall-course v-for="course in courses"
:course="course"
:key="course.id">
</overall-course>
</div>
</template>
+2 -2
View File
@@ -22,8 +22,8 @@ export class CourseUtils
// Skip courses without levels
if (course.level == 'None') return;
// Skip courses without assignments
if (course.assignments.length == 0) return;
// Skip courses without graded assignments
if (course.assignments.filter(a => a.complete == 'Complete').length == 0) return;
// Skip if there are no grading scale
// if (course.grading.method == 'NOT_GRADED') return;
-5
View File
@@ -4,11 +4,6 @@ export class HttpUtils
{
public token: string = '';
constructor (token: string)
{
this.token = token;
}
public post(node: string, body: any): Promise<any>
{
// Add token
+2
View File
@@ -17,7 +17,9 @@ export default class JsonUtils
result.push(
{
id: assignment.assignment_id,
scoreId: assignment.score_id,
type: assignment.assignment_type,
typeId: assignment.assignment_type_id,
description: assignment.assignment_description,
date: assignment._date,
complete: assignment.completion_status,