Compare commits

...

460 Commits

Author SHA1 Message Date
Hykilpikonna cfac8493cd [U] Pre-Release v0.3.5.697 2019-10-20 19:54:57 -04:00
Hykilpikonna 0d003a4f7e [O] Make new update clickable as well 2019-10-20 19:53:56 -04:00
Hykilpikonna 106a4759ae [O] Make clickable text cursor show as pointer 2019-10-20 19:53:42 -04:00
Hykilpikonna 06d09220c5 [O] Move clickable to global css 2019-10-20 19:46:19 -04:00
Hykilpikonna a19960b18f [O] Do nothing if not clickable 2019-10-20 19:44:06 -04:00
Hykilpikonna 656dd7d884 [+] Implement redirect on click in course-head 2019-10-20 19:42:06 -04:00
Hykilpikonna b965859537 [U] Use formatCourseIndex() in navigation 2019-10-20 19:41:50 -04:00
Hykilpikonna 707e96d2e9 [+] Encapsulate method to format course tab index 2019-10-20 19:41:28 -04:00
Hykilpikonna ab795674b2 [+] Add instance in App class 2019-10-20 19:36:38 -04:00
Hykilpikonna eb74feb659 [+] Create onClick function in course-head 2019-10-20 19:33:51 -04:00
Hykilpikonna 4b4c49b5c7 [+] Make courses in overall clickable 2019-10-20 19:29:52 -04:00
Hykilpikonna 1c134e02f9 [+] Add clickable prop to course-head 2019-10-20 19:29:18 -04:00
Hykilpikonna 85305f987f [O] Optimize course-head grid distribution 2019-10-20 19:23:12 -04:00
Hykilpikonna ec6e2b8c7e [F] Fix logical mistake 2019-10-20 19:22:55 -04:00
Hykilpikonna ab34435395 [U] Use VersionUtils.compare() in Login class 2019-10-20 19:17:21 -04:00
Hykilpikonna da96d846eb [+] Create function to compare version numbers 2019-10-20 19:11:22 -04:00
Hykilpikonna 9f6cb2658a [+] Create VersionUtils class 2019-10-20 19:00:47 -04:00
Hykilpikonna 33402012b6 [-] Remove deprecated file 2019-10-20 19:00:04 -04:00
Hykilpikonna 97cf1651f9 [+] Add MIN_SUPPORTED_VERSION 2019-10-20 18:59:26 -04:00
Hykilpikonna 97bfe69986 [O] Add logging before clearing cookies 2019-10-20 18:55:05 -04:00
Hykilpikonna b08fd7f433 [U] Use needToUpdateCookies() to check 2019-10-20 18:54:52 -04:00
Hykilpikonna 83c6a690ec [O] Optimize variable name lengths 2019-10-20 18:53:21 -04:00
Hykilpikonna cb54ae4dee [+] Create function to check version number 2019-10-20 18:53:03 -04:00
Hykilpikonna be2dcbf085 [O] Extend token saving period 2019-10-20 18:44:56 -04:00
Hykilpikonna 4df2726b95 [O] Make the chart full width (for now) 2019-10-20 18:40:35 -04:00
Hykilpikonna aa78e850bb [O] Adjust graph size 2019-10-20 18:39:50 -04:00
Hykilpikonna c05f18c12c [O] Add drop shadow 2019-10-20 18:38:16 -04:00
Hykilpikonna b4041a11a0 [O] Add cross tooltip pointer 2019-10-20 18:31:43 -04:00
Hykilpikonna bcf222a38b [O] Format x axis dates to MMM DD format 2019-10-20 18:28:07 -04:00
Hykilpikonna 7cfe928fcc [O] Adjust y label position 2019-10-20 18:25:12 -04:00
Hykilpikonna b5ad7c12e3 [O] Add '%' signs to y axis labels 2019-10-20 18:24:33 -04:00
Hykilpikonna 6286c5736e [O] Lighten legend label color 2019-10-20 18:20:35 -04:00
Hykilpikonna 0773d3ef0e [O] Make legend smaller 2019-10-20 18:20:21 -04:00
Hykilpikonna 7b912a9325 [O] Make title larger 2019-10-20 18:20:09 -04:00
Hykilpikonna 008155fa61 [O] Adjust legend icon width 2019-10-20 18:16:42 -04:00
Hykilpikonna 117cd9f568 [O] Adjust legend position 2019-10-20 18:16:15 -04:00
Hykilpikonna 3b14727f81 [O] Remove x axis name 2019-10-20 18:15:13 -04:00
Hykilpikonna 444a3733bd [O] Align legend to the bottom 2019-10-20 18:14:09 -04:00
Hykilpikonna de63ff9bb5 [+] Add legend 2019-10-20 18:13:56 -04:00
Hykilpikonna 2b2a4c59a8 [O] Adjust y-axis label position 2019-10-20 18:11:47 -04:00
Hykilpikonna 30f737bd7c [O] Center align y-axis label 2019-10-20 18:10:39 -04:00
Hykilpikonna 1e2c6ca66f [O] Make min x value of course-scatter a whole number 2019-10-20 18:04:43 -04:00
Hykilpikonna 7b13716ce3 [O] Make min x value of overall-line a whole number 2019-10-20 18:04:00 -04:00
Hykilpikonna 7a1b21a2ac [F] Fake course object usage to update computed value when tab switched 2019-10-20 17:36:12 -04:00
Hykilpikonna 2345bb6442 [F] Show only completed assignments 2019-10-20 17:30:00 -04:00
Hykilpikonna 47fd9e1db3 [O] Set max x value as today 2019-10-20 17:28:11 -04:00
Hykilpikonna f8eee081b3 [O] Adjust x axis label position 2019-10-20 17:26:28 -04:00
Hykilpikonna 84e0647c35 [O] Display x axis name 2019-10-20 17:23:22 -04:00
Hykilpikonna 60804dd98c [O] Add tooltip to scatter graph 2019-10-20 17:23:04 -04:00
Hykilpikonna 5789fac985 [-] Remove unnecessary :entend tag 2019-10-20 17:14:03 -04:00
Hykilpikonna 2a89c6316f [O] Override VE chart settings 2019-10-20 17:13:48 -04:00
Hykilpikonna 4c0a26a900 [-] Remove unused notification class 2019-10-20 17:02:22 -04:00
Hykilpikonna 6915617980 [+] Add inner top shadow to course card content 2019-10-20 17:01:58 -04:00
Hykilpikonna 0a09e14021 [-] Remove the todo 2019-10-20 16:58:48 -04:00
Hykilpikonna 34446494a9 [O] Round data 2019-10-20 13:06:30 -04:00
Hykilpikonna 8477c2f63b [O] Use percent score instead of 0 to 1 2019-10-20 13:00:52 -04:00
Hykilpikonna 105d1f7619 [+] Define colors 2019-10-20 12:59:32 -04:00
Hykilpikonna a4be712bd7 [F] Format date so that the chart can read it 2019-10-20 12:58:30 -04:00
Hykilpikonna 3a9a65920e [F] Use Array.from instead of map.forEach 2019-10-20 12:58:03 -04:00
Hykilpikonna ff62847758 [+] Debug with afterConfig() 2019-10-20 12:57:40 -04:00
Hykilpikonna 0207f617c2 [O] Optimize code format 2019-10-20 12:40:00 -04:00
Hykilpikonna 5c530952d3 [O] Add more colors 2019-10-20 12:39:46 -04:00
Hykilpikonna bdcefefd92 [O] Map assignments first 2019-10-20 12:12:25 -04:00
Hykilpikonna 68cebfa68c [O] Show tooltip 2019-10-20 12:12:00 -04:00
Hykilpikonna 94b337e772 [O] Change title of the chart 2019-10-20 12:06:39 -04:00
Hykilpikonna fd1f6223c0 [F] Fix date format 2019-10-20 12:06:29 -04:00
Hykilpikonna 0d86e461cd [+] Create function to format chart date 2019-10-20 12:03:01 -04:00
Hykilpikonna 9f06748b63 [+] Create format-utils 2019-10-20 11:59:41 -04:00
Hykilpikonna 9769fca6af [O] Label x and y axis 2019-10-20 11:57:37 -04:00
Hykilpikonna 416ef0991d [O] Make the x axis type time 2019-10-20 11:57:19 -04:00
Hykilpikonna 2150a563eb [F] Fix null case detection 2019-10-20 11:47:40 -04:00
Hykilpikonna 1ef08c17ec [F] Fix typo: 'course' instead of 'courses' 2019-10-20 11:46:34 -04:00
Hykilpikonna 15e375900c [+] Complete series 2019-10-20 11:45:42 -04:00
Hykilpikonna d70d54d3f7 [+] Create function to convert assignments to series data 2019-10-20 11:45:35 -04:00
Hykilpikonna 0159f639d2 [O] Optimize type with Map<string, Assignment[]> 2019-10-20 11:40:09 -04:00
Hykilpikonna 19d03536b5 [O] Specify return type 2019-10-20 11:36:35 -04:00
Hykilpikonna 214a716f16 [O] Clarify format in jsdocs 2019-10-20 11:35:11 -04:00
Hykilpikonna 1f5ecedf9f [+] Create function to map assignments 2019-10-20 11:34:48 -04:00
Hykilpikonna 3b52dab371 [+] Add course-scatter component to course-page 2019-10-20 09:53:01 -04:00
Hykilpikonna 40340a0abd [F] Fix "This dependency is not found" 2019-10-20 09:52:41 -04:00
Hykilpikonna c2311464f0 [+] Import course-scatter 2019-10-20 09:52:03 -04:00
Hykilpikonna f4f6fa2523 [+] Create course scatter vue component 2019-10-20 09:51:13 -04:00
Hykilpikonna 44d01eaec0 [O] Remove max height limit for course page 2019-10-20 09:48:30 -04:00
Hykilpikonna 300ff04f2e [F] Fix empty pathname detection with '/' 2019-10-14 22:14:46 -04:00
Hykilpikonna 6a34e9f706 [+] Add todo text 2019-10-14 22:13:22 -04:00
Hykilpikonna 97c8953dbd [-] Remove unnecessary overall-line.scss 2019-10-14 22:10:05 -04:00
Hykilpikonna 179d0bc567 [O] Make it scoped 2019-10-14 22:09:04 -04:00
Hykilpikonna 2d1242f3c0 [O] Inline overall-bar scss 2019-10-14 22:08:51 -04:00
Hykilpikonna b7f7e168b9 [O] Make css in unread-entry scoped 2019-10-14 22:07:47 -04:00
Hykilpikonna 83244ec496 [O] Make the css in overall-course and course-page scoped 2019-10-14 22:06:22 -04:00
Hykilpikonna eb3221fa4b [M] Move card padding to global css 2019-10-14 22:06:00 -04:00
Hykilpikonna 4e37ca4c44 [+] Add row on the expansion area 2019-10-14 21:36:57 -04:00
Hykilpikonna ae6172068e [+] Make course-page almost the same with overall-course 2019-10-14 21:35:55 -04:00
Hykilpikonna 65134c02af [+] Import course-head in course-page 2019-10-14 21:34:30 -04:00
Hykilpikonna fa9e1aae7c [O] Fix ' and " issue 2019-10-14 21:31:21 -04:00
Hykilpikonna 3d1401e1c2 [+] Add course-head element in overall-course 2019-10-14 20:33:25 -04:00
Hykilpikonna 8c102f5d5f [M] Move css to course-head 2019-10-14 20:33:05 -04:00
Hykilpikonna c4e1790444 [+] Import course-head in overall-course 2019-10-14 20:27:25 -04:00
Hykilpikonna 68c1fa1216 [M] Separate course-head from overall-course 2019-10-14 20:27:07 -04:00
Hykilpikonna eb094be9af [F] Move global css outside of overall scope 2019-10-14 20:26:13 -04:00
Hykilpikonna 8527e9860d [O] Make overall.scss scoped 2019-10-14 19:35:16 -04:00
Hykilpikonna ceb1ed1404 [O] Surround the course with a card 2019-10-14 19:34:12 -04:00
Hykilpikonna 968fa63f51 [O] Make course name font size 36px 2019-10-14 19:09:55 -04:00
Hykilpikonna 2d530d204e [O] Align text to the left 2019-10-14 19:08:21 -04:00
Hykilpikonna 65efde05ee [O] Add some margins 2019-10-14 19:08:12 -04:00
Hykilpikonna a5d261ac93 [+] Use grid to display basic info 2019-10-14 19:01:17 -04:00
Hykilpikonna b61cd3839a [O] Move v-if assignmentReady detection up an element 2019-10-14 18:45:01 -04:00
Hykilpikonna 665567bf88 [+] Bind the displayed course to the course page 2019-10-14 18:28:37 -04:00
Hykilpikonna a074a9fbed [+] Show course page only if select tab is a course 2019-10-14 18:27:37 -04:00
Hykilpikonna 0e30954f6e [+] Add course page 2019-10-14 18:27:09 -04:00
Hykilpikonna 0e98cffc64 [+] Update initial index 2019-10-14 18:26:26 -04:00
Hykilpikonna e7d5e766e3 [+] Add default path name when there are none 2019-10-14 18:02:02 -04:00
Hykilpikonna 88b0ef752c [+] Dynamically initialize first state based on pathname 2019-10-14 18:01:43 -04:00
Hykilpikonna 1a8fc9eab4 [-] Remove duplicate update 2019-10-14 17:57:56 -04:00
Hykilpikonna 76dd8f73e4 [O] Use updateIndex() instead 2019-10-14 17:57:43 -04:00
Hykilpikonna 4807c4babb [+] Encapsulate method to update index 2019-10-14 17:57:18 -04:00
Hykilpikonna 9b4f5291f0 [O] Use v-bind.sync to sync variable value 2019-10-14 17:57:04 -04:00
Hykilpikonna 5edc4c55f5 [-] Remove testing log 2019-10-14 16:43:21 -04:00
Hykilpikonna 563bf06b8e [-] Remove onNavigate event 2019-10-14 16:42:38 -04:00
Hykilpikonna cdaa2679d1 [M] Move pushState to navigation.ts as well 2019-10-14 16:42:09 -04:00
Hykilpikonna 4efac6023f [O] Bind activeIndex with selectedTab 2019-10-14 16:40:41 -04:00
Hykilpikonna c6e3806024 [M] Move history stuff to navigation.ts 2019-10-14 16:40:27 -04:00
Hykilpikonna e3df5b8e3b [+] Create history state listener 2019-10-14 16:35:00 -04:00
Hykilpikonna 5afc0aebd5 [+] Set state on start 2019-10-14 16:34:39 -04:00
Hykilpikonna d23446b409 [F] Push state after updating tab 2019-10-14 16:33:41 -04:00
Hykilpikonna bc63b457d3 [+] Clarify logging 2019-10-14 16:24:20 -04:00
Hykilpikonna 30a8d62402 [+] Keep last selected tabb 2019-10-14 16:23:16 -04:00
Hykilpikonna 349683de24 [F] Use absolute path for history 2019-10-14 09:40:18 -04:00
Hykilpikonna 06db7f48bd [F] Fix: can't replace all with replace() 2019-10-14 09:38:36 -04:00
Hykilpikonna 986a38d81d [O] Replace spaces in course name with '-' 2019-10-14 09:37:55 -04:00
Hykilpikonna 8b7ee75ca7 [+] Add course id to the navigation index 2019-10-14 09:36:37 -04:00
Hykilpikonna f59bed777b [O] Use all lowercase for course navigation 2019-10-14 09:36:02 -04:00
Hykilpikonna 87634f0df5 [+] Push history state on navigation 2019-10-14 09:32:19 -04:00
Hykilpikonna bb618e74c9 [+] Import course page in app 2019-10-14 09:31:54 -04:00
Hykilpikonna 92d2a7673b [O] Make text lighter 2019-10-13 22:25:48 -04:00
Hykilpikonna 232fe43eb5 [O] Add gradient to loading screen 2019-10-13 22:24:50 -04:00
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
Hykilpikonna 0345d37b2c [U] Pre-release v0.3.1.382 2019-10-05 14:11:32 -04:00
Hykilpikonna 97818c45f5 [-] Remove drop shadow 2019-10-05 14:10:26 -04:00
Hykilpikonna 1a09c7311e [O] Make font size smaller 2019-10-05 14:10:17 -04:00
Hykilpikonna b658f6f707 [O] Make text italic 2019-10-05 14:10:08 -04:00
Hykilpikonna 1d63e4865b [M] Move main color to theme 2019-10-05 14:05:26 -04:00
Hykilpikonna 78fbd342d9 [O] Apply nowrap to all cards 2019-10-05 14:04:06 -04:00
Hykilpikonna 141c192017 [+] Add github link to splash 2019-10-05 14:00:07 -04:00
Hykilpikonna 87e44b83f7 [+] Add github link constant 2019-10-05 13:59:50 -04:00
Hykilpikonna 1064831379 [O] Separate version as a constant 2019-10-05 13:59:37 -04:00
Hykilpikonna 1e42ef7873 [O] Add text shadow 2019-10-05 13:54:56 -04:00
Hykilpikonna c8327f3774 [O] Replace hex with var 2019-10-05 13:51:26 -04:00
Hykilpikonna 69cd4ff050 [+] Use default theme in base div 2019-10-05 13:51:05 -04:00
Hykilpikonna 027f8bfd34 [+] Create theme css class 2019-10-05 13:50:50 -04:00
Hykilpikonna 70ede22c18 [O] Remove space between number and '%' 2019-10-05 13:45:04 -04:00
Hykilpikonna fd74298b0b [+] Add some right margin 2019-10-05 13:44:35 -04:00
Hykilpikonna d47bae00ff [+] Change color of unread text as well 2019-10-05 13:43:32 -04:00
Hykilpikonna 0c91b1b598 [U] Update css implementation 2019-10-05 13:42:13 -04:00
Hykilpikonna 6ba789c7cf [M] Move unread class up a level 2019-10-05 13:41:56 -04:00
Hykilpikonna 54b70f6a1c [F] Fix inversed condition 2019-10-05 13:39:08 -04:00
Hykilpikonna ac32a02ff4 [O] Make 'update' plural only when count >= 2 2019-10-05 13:38:22 -04:00
Hykilpikonna 993578277e [+] Add 'new update' text 2019-10-05 13:38:00 -04:00
Hykilpikonna 48fb8c7d4c [O] Optimize unread count with caching 2019-10-05 13:36:56 -04:00
Hykilpikonna 0f6f27aa15 [O] Add some paddings to make it larger 2019-10-05 13:34:56 -04:00
Hykilpikonna b2947e9ef6 [+] Add shadow 2019-10-05 13:18:17 -04:00
Hykilpikonna c5ef8a297b [F] Fix css syntax: Stacked class vs stacked element 2019-10-05 13:16:31 -04:00
Hykilpikonna 02ca6b8d47 [+] Add dynamic coloring 2019-10-05 13:15:20 -04:00
Hykilpikonna 98b92b4dfb [+] Add dynamic class based on unread count 2019-10-05 13:14:03 -04:00
Hykilpikonna 1c2afdfa52 [O] Add block around the update number 2019-10-05 13:13:45 -04:00
Hykilpikonna 55b4bd9173 [+] Encapsulate method to count unread assignments 2019-10-05 13:10:34 -04:00
Hykilpikonna e422c03ca5 [-] Remove centering 2019-10-05 13:00:02 -04:00
Hykilpikonna 831ef16a2f [+] Display unread 2019-10-05 12:59:45 -04:00
Hykilpikonna 0deb0ed719 [F] Fix key typo: is_unread instead of unread 2019-10-05 12:56:10 -04:00
Hykilpikonna f3d44ceda2 [+] Parse id and unread 2019-10-05 10:24:42 -04:00
Hykilpikonna cb11db6201 [+] Add field id and unread to Assignment type 2019-10-05 10:23:46 -04:00
Hykilpikonna b52f3d2617 [M] Rename type Grade to type Assignment 2019-10-05 10:22:40 -04:00
Hykilpikonna 39cd5bf1a2 [F] Fix grid misplacement problem 2019-10-02 08:13:17 -04:00
Hykilpikonna 19f03717bc [O] Go back to using grid 2019-10-02 08:12:53 -04:00
Hykilpikonna 6d728c25ae [O] Center grade display 2019-10-01 21:45:36 -04:00
Hykilpikonna c8daa2a06e [+] Fix the numeric grade to 2 digits 2019-10-01 21:41:57 -04:00
Hykilpikonna 4d41e679dd [O] Make grade font size match Veracross 2019-10-01 21:29:56 -04:00
Hykilpikonna acfebf9ff3 [+] Show course card for every course 2019-10-01 21:29:35 -04:00
Hykilpikonna 5af1b1e5a1 [O] Add auto margin top and bottoms 2019-10-01 21:19:22 -04:00
Hykilpikonna bc9a4f00c1 [+] Align left and right 2019-10-01 21:19:08 -04:00
Hykilpikonna f13f3a155c [-] Remove the grid 2019-10-01 21:09:50 -04:00
Hykilpikonna a19edb8aa7 [+] Display numeric grade and letter grade 2019-10-01 21:01:15 -04:00
Hykilpikonna 6a0500acb2 [-] Remove unnecessary span 2019-10-01 20:54:29 -04:00
Hykilpikonna 96af69508f [O] Limit course name length 2019-10-01 20:50:25 -04:00
Hykilpikonna 3fbc9764e9 [O] Make teacher name italicised 2019-10-01 20:50:12 -04:00
Hykilpikonna a79dcb76af [O] Make teacher name font size match Veracross 2019-10-01 20:49:54 -04:00
Hykilpikonna 86c2fd5df7 [+] Add underline effect on hover 2019-10-01 20:49:18 -04:00
Hykilpikonna 07eaeef133 [+] Add margin to the beginning of course name 2019-10-01 20:49:03 -04:00
Hykilpikonna d1bd0a5667 [O] Change font size to match Veracross 2019-10-01 20:48:44 -04:00
Hykilpikonna 49dad14c84 [O] Adjust spacing 2019-10-01 20:47:57 -04:00
Hykilpikonna 50e3c345d5 [O] Clarify css selector 2019-10-01 20:40:18 -04:00
Hykilpikonna a444dbb32a [+] Add cols to display course name and teacher name 2019-10-01 20:39:53 -04:00
Hykilpikonna 03e212bd37 [+] Add margins to the navigation bar 2019-10-01 20:24:54 -04:00
Hykilpikonna 0325eb13d5 [F] Fix css priority issue 2019-10-01 20:17:37 -04:00
Hykilpikonna bfcb80aa64 [+] Add a title but comment it out 2019-10-01 20:10:48 -04:00
Hykilpikonna 91a6c0c6e4 [+] Optimize card formatting 2019-10-01 20:01:56 -04:00
Hykilpikonna 845cc94513 [+] Add a card in course element 2019-10-01 20:01:47 -04:00
Hykilpikonna 21ccaceb53 [+] Add a testing course element 2019-10-01 20:01:37 -04:00
Hykilpikonna b9f63171f2 [+] Create overall-course component 2019-10-01 19:44:51 -04:00
Hykilpikonna 636d92d1a0 [M] Rename and correct some misc css class names 2019-10-01 19:44:24 -04:00
Hykilpikonna 199ab9e00c [M] Rename graph-average to overall-bar 2019-10-01 19:37:20 -04:00
Hykilpikonna 77541764d1 [M] Rename graph-overall to overall-line 2019-10-01 19:36:09 -04:00
Hykilpikonna 53ae74f9c4 [O] Use absolute positioning to center what's in the center 2019-10-01 19:33:11 -04:00
Hykilpikonna 5bc1d6ba48 [O] Put sign-out button on the right 2019-10-01 19:30:41 -04:00
Hykilpikonna 831ddcf84e [-] Remove debug output 2019-10-01 19:27:00 -04:00
Hykilpikonna 35a85d8e83 [U] Release v0.2.3.315 2019-10-01 19:19:27 -04:00
Hykilpikonna 71b0a6e4dd [-] Remove debug output 2019-10-01 19:18:51 -04:00
Hykilpikonna d4fbd04466 [F] Fix grading history lower than actual 2019-10-01 19:18:33 -04:00
Hykilpikonna 31b3814b1e [O] Ignore 0 when calculating the score 2019-10-01 19:02:41 -04:00
Hykilpikonna 1aff2b0a68 [-] Remove debug output 2019-10-01 19:02:10 -04:00
Hykilpikonna 2567fcadbd [+] Encapsulate method to calculate total-mean average 2019-10-01 18:41:42 -04:00
Hykilpikonna d9e0e9f84e [F] Fix another null case 2019-10-01 18:41:14 -04:00
Hykilpikonna 59b31ea43f [F] Fix key word typo 2019-10-01 18:41:04 -04:00
Hykilpikonna 2c8b3e0f84 [F] Fix null case 2019-10-01 18:40:54 -04:00
Hykilpikonna 6910a7b5ea [F] Fix null pointer caused by grading not existing 2019-10-01 18:30:20 -04:00
Hykilpikonna cbdcfc4ca1 [+] Check gradings after checking assignments 2019-10-01 18:30:02 -04:00
Hykilpikonna feabc336c1 [+] Create method to check course gradings 2019-10-01 18:29:50 -04:00
Hykilpikonna b5b9f14a49 [U] Pre-release v0.2.2.303 2019-09-30 21:16:53 -04:00
Hykilpikonna fc93cd1248 [+] Skip if not graded 2019-09-30 21:05:39 -04:00
Hykilpikonna 6e58c634a1 [F] Correct course average grade graph calculation 2019-09-30 21:05:29 -04:00
Hykilpikonna 10cca344c7 [M] Copy old course calculation method to deprecated 2019-09-30 21:05:07 -04:00
Hykilpikonna cdf58ea3a0 [O] Specify type for weighting map 2019-09-30 21:04:47 -04:00
Hykilpikonna d97c80afbb [U] Update course model to match the update 2019-09-30 19:25:59 -04:00
Hykilpikonna 8c7d028f5b [R] Update screenshot 2019-09-29 19:51:19 -04:00
Hykilpikonna 19ba8ec7e6 [U] Pre-release v0.2.1.295 2019-09-29 19:45:22 -04:00
Hykilpikonna 6937952f3a [O] Optimize alignment 2019-09-29 19:44:38 -04:00
Hykilpikonna 485717d3ef [+] Dynamic min value 2019-09-29 19:42:26 -04:00
Hykilpikonna 3f3e46bec5 [O] Make graph-overall smoother 2019-09-29 19:42:16 -04:00
Hykilpikonna 1494315e0c [O] Optimize wording 2019-09-29 19:14:39 -04:00
Hykilpikonna 76eb8168ce [O] Align the two graph titles 2019-09-29 19:14:27 -04:00
Hykilpikonna e4a1c4973d [O] Rotate text to 90 degrees 2019-09-29 19:14:12 -04:00
Hykilpikonna b22fc41582 [+] Add title to course gpa graph 2019-09-29 19:14:02 -04:00
Hykilpikonna 0e1264d938 [O] Make the full grade color gray 2019-09-29 18:29:52 -04:00
Hykilpikonna a94a6db4b7 [O] Make the bar color match the line graph color 2019-09-29 18:29:32 -04:00
Hykilpikonna 18b5b7de77 [O] Separate the generation of the gp dataset 2019-09-29 18:28:33 -04:00
Hykilpikonna 28d4e5d871 [F] Fix typo on assignment sign 2019-09-29 18:09:32 -04:00
Hykilpikonna cc5b7b2793 [O] Remove dataset, move data to series 2019-09-29 18:02:40 -04:00
Hykilpikonna 7b4ced4e94 [O] Display larger data on farthest layer 2019-09-29 17:46:00 -04:00
Hykilpikonna 70e6debe82 [+] Stack the bars in graph 2019-09-29 17:44:08 -04:00
Hykilpikonna e0c4426ebb [O] Optimize series generation with [].map 2019-09-29 17:43:01 -04:00
Hykilpikonna 495e776971 [O] Optimize code length 2019-09-29 17:39:21 -04:00
Hykilpikonna fc625c8edb [+] Truncate text if too long 2019-09-29 17:38:53 -04:00
Hykilpikonna 6c1623cec5 [+] Show axis label 2019-09-29 17:31:37 -04:00
Hykilpikonna a9a9cf5f11 [O] Make bar graph vertical 2019-09-29 17:31:29 -04:00
Hykilpikonna d8f276005d [O] Make the two graphs the same width 2019-09-29 17:20:07 -04:00
Hykilpikonna 5c9e67478f [+] Rebuild entire average graph from settings 2019-09-29 17:17:23 -04:00
Hykilpikonna 5e0394f11c [+] Create a theme constant 2019-09-29 16:28:44 -04:00
Hykilpikonna 774e436c9c [F] Fix typo in :data bind method 2019-09-29 16:14:17 -04:00
Hykilpikonna 8b653e3317 [+] GraphAverage: Return graph 2019-09-29 16:13:57 -04:00
Hykilpikonna 9731d4e380 [+] GraphAverage: Map GPA and MaxGPA for each course 2019-09-29 16:13:52 -04:00
Hykilpikonna e3ca21ec29 [+] GraphAverage: Make column list 2019-09-29 16:13:14 -04:00
Hykilpikonna a89c29dc53 [F] Fix class name typo 2019-09-29 16:04:48 -04:00
Hykilpikonna 87a59416ec [O] Optimize minDate calculation with array.map() and Math.min 2019-09-29 16:04:38 -04:00
Hykilpikonna 8243312179 [O] Optimize column generation with array.map() 2019-09-29 15:48:28 -04:00
Hykilpikonna 3dcc1b8319 [+] Add zome bar 2019-09-29 15:34:17 -04:00
Hykilpikonna 899ff22677 [O] Hide legend for now 2019-09-29 15:33:14 -04:00
Hykilpikonna 788f51399a [O] Center title 2019-09-29 15:33:05 -04:00
Hykilpikonna 575dbdf765 [-] Remove duplicate title in html 2019-09-29 15:32:58 -04:00
Hykilpikonna 1659964011 [O] Show title in graph settings 2019-09-29 15:32:46 -04:00
Hykilpikonna 02533f6b07 [+] Add graph-average to overall page 2019-09-29 15:23:51 -04:00
Hykilpikonna 68a91e5eb8 [+] Create average graphs 2019-09-29 15:18:46 -04:00
Hykilpikonna 1eb6128aac [O] Optimize type declaration 2019-09-29 15:17:14 -04:00
Hykilpikonna fbd59f9ec3 [-] Remove unnecessary var declaration in getGPA() 2019-09-29 15:12:47 -04:00
Hykilpikonna 7eb7838f66 [M] Move convertChart() to graph-overall.ts 2019-09-29 15:12:05 -04:00
Hykilpikonna 6459e1c09b [O] Make the legend icon a circle 2019-09-29 15:09:15 -04:00
Hykilpikonna 4461ef835f [U] Pass in filtered courses instead 2019-09-29 15:08:30 -04:00
Hykilpikonna 6ee207d754 [+] Filter courses after assignments are retrieved 2019-09-29 15:07:01 -04:00
Hykilpikonna 3c0c0d5f1b [-] Remove unnecessary jsdoc @param declaration 2019-09-29 15:02:24 -04:00
Hykilpikonna bc8fcc021d [M] Move course filtering to course-utils.ts 2019-09-29 15:01:47 -04:00
Hykilpikonna e9a6cfe5c5 [O] Make legend font size smaller 2019-09-29 14:47:47 -04:00
Hykilpikonna 0e92cedf54 [+] Add title but doesn't show 2019-09-29 14:27:25 -04:00
Hykilpikonna a73d6b0399 Revert "[O] Use vue-echarts instead of v-charts"
This reverts commit d254706a21.
2019-09-29 12:45:06 -04:00
Hykilpikonna 8042765ff5 Revert "[-] Remove v-charts dependency"
This reverts commit 8978b7ca7b.
2019-09-29 12:45:03 -04:00
Hykilpikonna 74a033fb5d Revert "[+] Import vue-echarts"
This reverts commit b78c5b4f5b.
2019-09-29 12:44:57 -04:00
Hykilpikonna cc4378d905 Revert "[+] Add vue-echarts transpile dependencies"
This reverts commit a526946b83.
2019-09-29 12:44:55 -04:00
Hykilpikonna 0fd3696342 Revert "[U] Update overall graph component"
This reverts commit c262584e2f.
2019-09-29 12:44:52 -04:00
Hykilpikonna 3de4b1f6e6 Revert "[+] Add a graph title"
This reverts commit 610d1d190d.
2019-09-29 12:44:50 -04:00
Hykilpikonna 610d1d190d [+] Add a graph title 2019-09-28 17:55:44 -04:00
Hykilpikonna c262584e2f [U] Update overall graph component 2019-09-28 17:55:35 -04:00
Hykilpikonna a526946b83 [+] Add vue-echarts transpile dependencies 2019-09-28 17:52:32 -04:00
Hykilpikonna b78c5b4f5b [+] Import vue-echarts 2019-09-28 17:50:42 -04:00
Hykilpikonna 8978b7ca7b [-] Remove v-charts dependency 2019-09-28 17:47:18 -04:00
Hykilpikonna d254706a21 [O] Use vue-echarts instead of v-charts 2019-09-28 17:47:02 -04:00
41 changed files with 1623 additions and 261 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ This is a website that generates visual representation of students' grade data o
**Here's how it looks like right now:** *(Now all of you know my grades ;-;)*
![](https://i.imgur.com/xl3Q4Nt.jpg)
![](https://user-images.githubusercontent.com/22280294/65841599-155ead00-e2f2-11e9-9d9f-c2f23c45d9a4.png)
<br>
+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>
+70 -5
View File
@@ -1,8 +1,73 @@
#app
{
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
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;
}
// ##############
// # Global CSS #
// ##############
.el-card
{
margin: 10px;
padding: 0;
}
.el-card.large
{
height: 494px;
}
// Fix padding
.el-card__body
{
padding-top: 0 !important;
padding-bottom: 0 !important;
}
// Vertical centering
.vertical-center
{
// Vertical center
display: flex;
justify-content: center;
flex-direction: column;
}
// Remove card padding for styling issues
div.el-card.course-card > div.el-card__body
{
padding-right: 0 !important;
padding-left: 0 !important;
}
// Clickable text
.clickable:hover
{
text-decoration: underline;
cursor: pointer;
}
+109 -38
View File
@@ -6,19 +6,29 @@ import Constants from '@/constants';
import JsonUtils from '@/utils/json-utils';
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';
import CoursePage from '@/pages/course/course-page';
/**
* Objects of this interface represent assignment grades.
*/
export interface Grade
export interface Assignment
{
id: number,
scoreId: number,
type: string,
typeId: number,
description: string,
date: string,
complete: string,
include: boolean,
display: boolean,
unread: boolean,
scoreMax: number,
score: number
}
@@ -40,11 +50,17 @@ export interface Course
level: string,
scaleUp: number,
assignments: Grade[]
grading:
{
method: string,
weightingMap: {[index: string]: number}
}
assignments: Assignment[]
}
@Component({
components: {Login, Navigation, Overall},
components: {Login, Navigation, Overall, Loading, CoursePage},
})
export default class App extends Vue
{
@@ -54,6 +70,9 @@ export default class App extends Vue
// List of course that the student takes
public courses: Course[] = [];
// List of course that should be displayed
public filteredCourses: Course[] = [];
// Currently selected tab
public selectedTab: string = 'overall';
@@ -63,8 +82,17 @@ 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();
// Instance
public static instance: App;
/**
* This is called when the instance is created.
@@ -73,6 +101,9 @@ export default class App extends Vue
{
// Show splash
console.log(Constants.SPLASH);
// Update instance
App.instance = this;
}
/**
@@ -85,11 +116,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();
@@ -100,7 +134,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)
@@ -111,27 +149,24 @@ 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})`));
}
/**
* Load the assignments of the courses
*
* @param courses Courses Json
*/
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)
@@ -140,50 +175,86 @@ 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(() =>
{
// When the assignments are ready
this.assignmentsReady = true;
// Filter courses
this.filteredCourses = CourseUtils.getGradedCourses(this.courses);
// Check grading algorithms
this.checkGradingAlgorithms();
});
}
/**
* Are assignments ready or not
*
* @returns boolean Ready or not
* Check the courses' grading algorithms. (Total-mean or percent-type)
*/
private isAssignmentsReady(): boolean
private checkGradingAlgorithms()
{
for (const course of this.courses)
// Show loading message
this.logLoading('4. Checking grading algorithms...');
// Loop through all the courses
for (const course of this.filteredCourses)
{
if (course.assignments == null) return false;
// Check if total-average grade is the same with percent-type grade
if (course.numericGrade == +GPAUtils.getTotalMeanAverage(course).toFixed(2))
{
course.grading = {method: 'TOTAL_MEAN', weightingMap: {}};
}
else
{
// Request grading scheme for this course
App.http.post('/grading', {'assignmentsId': course.assignmentsId}).then(response =>
{
// Check success
if (response.success)
{
// Add it to course
course.grading = response.data;
}
else throw new Error(response.data);
})
.catch(e => this.showError(`Error: Grading data failed to load.\n(${e})`))
}
}
return true;
// Wait for done
pWaitFor(() => this.filteredCourses.every(c => c.grading != undefined)).then(() =>
{
// When the assignments are ready
this.assignmentsReady = true;
// Remove loading
this.logLoading('');
})
}
/**
* This is called when a navigation tab is clicked
* Log a message to loading screen
*
* @param tab Tab name
* @param message Message
*/
public onNavigate(tab: string)
private logLoading(message: string)
{
// Debug output TODO: Remove this
console.log(tab);
if (message == '') this.loading = '';
else this.loading += '\n' + message;
}
// Update selected tab
this.selectedTab = tab;
/**
* Show error message on loading screen
*
* @param message Error message
*/
private showError(message: string)
{
this.loadingError = true;
this.loading = message;
}
/**
+14 -7
View File
@@ -1,14 +1,21 @@
<template>
<div id="app">
<login v-if="showLogin" v-on:login:token="onLogin" :http="http"></login>
<navigation :courses="courses"
v-on:sign-out="signOut()"
v-on:navigation:select="onNavigate">
<div id="app" class="theme-default">
<login v-if="showLogin" v-on:login:token="onLogin"></login>
<navigation :courses="filteredCourses"
:activeIndex.sync="selectedTab"
v-on:sign-out="signOut">
</navigation>
<div id="app-content">
<overall :courses="courses" v-if="selectedTab === 'overall' && assignmentsReady"></overall>
<div id="app-content" v-if="assignmentsReady && loading === ''">
<overall v-if="selectedTab === 'overall'"
:courses="filteredCourses">
</overall>
<course-page v-if="selectedTab.split('/')[0] === 'course'"
:course="filteredCourses.find(c => +c.id === +selectedTab.split('/')[1])">
</course-page>
</div>
<loading v-if="loading !== ''" :text="loading" :error="loadingError"></loading>
</div>
</template>
+116
View File
@@ -0,0 +1,116 @@
<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;
box-shadow: inset 0 0 1px 1px rgba(0,0,0,.1);
background: -webkit-linear-gradient(left, rgba(95, 18, 72, 0.4), rgba(42, 81, 117, 0.4) 100%);
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: #f9f9f9;
}
#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>
+28 -5
View File
@@ -1,6 +1,8 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Constants from '@/constants';
import {HttpUtils} from '@/utils/http-utils';
import App from '@/components/app/app';
import VersionUtils from '@/utils/version-utils';
/**
* This component handles user login, and obtains data from the server.
@@ -17,14 +19,20 @@ 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.needToUpdateCookies())
{
console.log('Version Updated! Clearing cookies...');
// Clear all cookies
this.$cookies.keys().forEach(key => this.$cookies.remove(key));
}
// Check login cookies
if (this.$cookies.isKey('va.token'))
{
@@ -33,6 +41,20 @@ export default class Login extends Vue
}
}
/**
* Check version number
*
* @returns boolean Need to clear cookies or not
*/
public needToUpdateCookies(): boolean
{
// Version doesn't exist
if (!this.$cookies.isKey('va.version')) return true;
// If the current version is less than the min supported version
return VersionUtils.compare(this.$cookies.get('va.version'), Constants.MIN_SUPPORTED_VERSION) == -1;
}
/**
* On click, sends username and password to the server.
*/
@@ -42,14 +64,15 @@ 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
if (response.success)
{
// Save token to cookies
this.$cookies.set('va.token', response.data, '7d');
this.$cookies.set('va.token', response.data, '27d');
this.$cookies.set('va.version', Constants.VERSION);
// Call custom event with token
this.$emit('login:token', response.data);
+33
View File
@@ -15,3 +15,36 @@
border-bottom-width: 0;
}
}
#sign-out-button
{
// Float right
position: absolute;
right: 0;
// Set width and height
height: 60px;
width: 110px;
}
#nav-title
{
// Float left
position: absolute;
left: 0;
// Set height
height: 60px;
// Center text
align-items: center;
// Margins
margin-left: 14px;
margin-right: 8px;
// Font
font-size: 1.25rem;
display: inline-flex;
}
+53 -4
View File
@@ -1,5 +1,7 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import Constants from '@/constants';
import {Course} from '@/components/app/app';
import {CourseUtils} from '@/utils/course-utils';
/**
* This component is the top navigation bar
@@ -9,10 +11,41 @@ import Constants from '@/constants';
})
export default class Navigation extends Vue
{
public activeIndex: string = 'overall';
// @ts-ignore
@Prop() activeIndex: string;
@Prop() courses: any;
/**
* This is called when the instance is created.
*/
public created()
{
// Set history state
let url = window.location.pathname;
if (url == '/' || url == '') url = '/overall';
window.history.replaceState({lastTab: url.substring(1)}, '', url);
// Update initial index
this.updateIndex(url.substring(1));
// Create history state listener
window.onpopstate = e =>
{
if (e.state)
{
// Restore previous tab
console.log(`onPopState: Current: ${this.activeIndex}, Previous: ${e.state.lastTab}`);
this.updateIndex(e.state.lastTab);
}
};
}
public formatCourseIndex(course: Course)
{
return CourseUtils.formatTabIndex(course);
}
/**
* This function is called when the selection changes.
*
@@ -22,10 +55,26 @@ export default class Navigation extends Vue
public onSelect(index: string, indexPath: string)
{
// Update active index
this.activeIndex = index;
this.updateIndex(index);
// Call custom event
this.$emit('navigation:select', this.activeIndex);
// Debug output TODO: Remove this
console.log(`onNavigate: Previous: ${this.activeIndex}, New: ${index}`);
// Check url
let url = `/${index}`;
// Push history state
window.history.pushState({lastTab: index}, '', url);
}
/**
* Update index
*
* @param newIndex New index
*/
private updateIndex(newIndex: string)
{
this.$emit('update:activeIndex', newIndex);
}
/**
+7 -2
View File
@@ -1,13 +1,18 @@
<template>
<div id="navigation">
<el-menu class="centered" :default-active="activeIndex" mode="horizontal" @select="onSelect">
<el-menu style="margin-bottom: 10px;" class="centered" mode="horizontal"
:default-active="activeIndex" @select="onSelect">
<!--div id="nav-title">
Veracross Analyzer
</div-->
<el-menu-item index="overall">Overall</el-menu-item>
<el-submenu index="courses">
<template slot="title">Courses</template>
<el-menu-item v-for="course in courses"
:index="`course-${course.name}`"
:index="formatCourseIndex(course)"
:key="course.name">{{course.name}}</el-menu-item>
</el-submenu>
+44 -4
View File
@@ -3,15 +3,55 @@
*/
export default class Constants
{
/**
* Base url for api access
*/
/** Base url for api access */
public static API_URL: string = 'https://va.hydev.org/api';
/** Current version */
public static VERSION: string = '0.3.5.697';
/** Minimum version that still supports the same cookies */
public static MIN_SUPPORTED_VERSION: string = '0.3.4.561';
public static GITHUB: string = 'https://github.com/HyDevelop/VeracrossAnalyzer.Client';
public static SPLASH: string =
'. , ,---. | \n' +
'| |. , |---|,---.,---.| , .,---,,---.,---.\n' +
' \\ / >< | || |,---|| | | .-\' |---\'| \n' +
' `\' \' ` ` \'` \'`---^`---\'`---|\'---\'`---\'` \n' +
' v0.1.2.236 `---\' '
' `---\' \n' +
` Version v${Constants.VERSION} by Hykilpikonna (YGui21)\n` +
` Github: ${Constants.GITHUB}`;
// Graph Theme
public static THEME =
{
// Colors
colors:
[
'#19d4ae',
'#5ab1ef',
'#fa6e86',
'#ffb980',
'#0067a6',
'#c4b4e4',
'#d87a80',
'#9cbbff',
'#d9d0c7',
'#87a997',
'#d49ea2',
'#5b4947',
'#7ba3a8',
'#fc97af',
'#919e8b',
'#d7ab82',
'#6e7074',
'#61a0a8',
'#efa18d',
'#787464',
'#cc7e63',
'#724e58',
'#4b565b'
]
}
}
+20
View File
@@ -0,0 +1,20 @@
// Card
.el-card.course-card
{
// Margins
margin-right: 20px;
margin-left: 20px;
// Limit name length
white-space: nowrap;
// Expansion color
background: #f4f6f9;
}
.course-card-content.expand
{
// 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);
}
+29
View File
@@ -0,0 +1,29 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Assignment, Course} from '@/components/app/app';
import CourseHead from '@/pages/overall/overall-course/course-head/course-head.vue';
import CourseScatter from '@/pages/course/course-scatter/course-scatter';
@Component({
components: {CourseHead, CourseScatter}
})
export default class CoursePage extends Vue
{
// @ts-ignore
@Prop({required: true}) course: Course;
private unread: number = -1;
private unreadAssignments: Assignment[] = [];
/**
* Count the number of unread assignments with cache
*/
countUnread(): number
{
if (this.unread == -1)
{
this.unreadAssignments = this.course.assignments.filter(a => a.unread);
return this.unread = this.unreadAssignments.length;
}
else return this.unread;
}
}
+21
View File
@@ -0,0 +1,21 @@
<template>
<el-card id="course-card" class="course-card">
<course-head :course="course" :unread="countUnread()"></course-head>
<div class="course-card-content expand">
<el-row>
<el-col :span="24">
<el-card class="large overall-line-card vertical-center">
<course-scatter :course="course"></course-scatter>
</el-card>
</el-col>
<el-col :span="0">
</el-col>
</el-row>
</div>
</el-card>
</template>
<script src="./course-page.ts" lang="ts"></script>
<style src="./course-page.scss" lang="scss" scoped></style>
@@ -0,0 +1,157 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Assignment, Course} from '@/components/app/app';
import {GPAUtils} from '@/utils/gpa-utils';
import Constants from '@/constants';
import {FormatUtils} from '@/utils/format-utils';
import moment from 'moment';
@Component({
})
export default class CourseScatter extends Vue
{
// @ts-ignore
@Prop({required: true}) course: Course;
/**
* Override options
*
* @param options Original options (Unused)
*/
afterConfig(options: any)
{
return this.chartSettings;
}
/**
* Generate settings
*/
get chartSettings()
{
// Map assignments
let map = this.mapAssignments();
let itemStyle =
{
normal:
{
opacity: 0.8,
shadowBlur: 10,
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowColor: 'rgba(0, 0, 0, 0.2)'
}
};
// Create settings
let settings =
{
// Color
color: Constants.THEME.colors,
// Title
title:
{
show: true,
textStyle:
{
fontSize: 13
},
text: 'Assignments',
subtext: 'Assignment scores for ' + this.course.name,
x: 'center'
},
// X axis represents course names
xAxis:
{
type: 'time',
axisLabel:
{
formatter: (name: any) => moment(name).format('MMM DD')
},
max: FormatUtils.toChartDate(new Date())
},
// Y axis represents GPAs and MaxGPAs
yAxis:
{
type: 'value',
name: 'Percentage Score',
nameLocation: 'center',
nameGap: 38,
axisLabel:
{
formatter: (name: any) => name + '%'
},
max: 100,
min: (value: any) => Math.floor(value.min) - 5
},
// Tooltip
tooltip:
{
trigger: 'axis',
axisPointer:
{
type: 'cross'
}
},
legend:
{
bottom: 24,
itemWidth: 14,
textStyle:
{
color: '#777',
fontSize: 11
}
},
// Data
series: Array.from(map, ([type, assignments]) =>
{
return {
type: 'scatter',
name: type,
data: CourseScatter.assignmentsData(assignments),
itemStyle: itemStyle
}
})
};
return settings;
}
/**
* Map assignments to {assignmentType, [assignment]} format.
*/
private mapAssignments(): Map<string, Assignment[]>
{
// Define map
let map = new Map();
// Move data to map
this.course.assignments.forEach(a =>
{
// Null case, create empty array
if (!map.has(a.type)) map.set(a.type, []);
// Put data
map.get(a.type).push(a);
});
return map;
}
/**
* Convert assignments to series data
*
* @param assignments Assignments
*/
private static assignmentsData(assignments: Assignment[])
{
return assignments.filter(a => a.complete == 'Complete')
.map(a => [FormatUtils.toChartDate(a.date), (a.score / a.scoreMax * 100).toFixed(2)]);
}
}
@@ -0,0 +1,16 @@
<template>
<div id="course-scatter">
<ve-scatter height="450px" class="graph" :extend="{heyIUsedCourseObject: this.course.name}" :after-config="afterConfig"></ve-scatter>
</div>
</template>
<script src="./course-scatter.ts" lang="ts"></script>
<style lang="scss" scoped>
#overall-bar
{
.graph
{
margin-top: 50px;
}
}
</style>
@@ -1,21 +0,0 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Course} from '@/components/app/app';
@Component({
})
export default class GraphOverall extends Vue
{
@Prop({required: true}) chart: any;
private settings =
{
series:
{
smooth: false
},
yAxis:
{
min: 70
}
}
}
@@ -1,9 +0,0 @@
<template>
<div id="graph-overall">
<p>Your average score graph all time:</p>
<ve-line :data="chart" :extend="settings"></ve-line>
</div>
</template>
<script src="./graph-overall.ts" lang="ts"></script>
<style src="./graph-overall.scss" lang="scss"></style>
@@ -0,0 +1,109 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Course} from '@/components/app/app';
import {GPAUtils} from '@/utils/gpa-utils';
import Constants from '@/constants';
@Component({
})
export default class OverallBar extends Vue
{
// @ts-ignore
@Prop({required: true}) courses: Course[];
/**
* Generate settings
*/
get chartSettings()
{
let settings =
{
// Title
title:
{
show: true,
textStyle:
{
fontSize: 12
},
text: 'Course GPA',
subtext: 'Current GPA for every course',
x: 'center'
},
// X axis represents course names
xAxis:
{
type: 'category',
axisLabel: {
interval: 0,
inside: false,
rotate: 90,
// Truncate text length
formatter: (value: string) => value.length <= 16 ? value : value.substr(0, 14) + '...'
},
},
// Y axis represents GPAs and MaxGPAs
yAxis:
{
type: 'value'
},
// Data
series:
[
{
type: 'bar',
barGap: '-100%',
data: this.courses.map(course =>
{
return {value: [course.name, GPAUtils.getGP(course, 'A+')],
itemStyle: {color: '#d8d8d8'}}
}),
},
{
type: 'bar',
barGap: '-100%',
data: this.generateGPData(),
label:
{
show: true,
rotate: 90
}
}
],
// Disable tooltip
tooltip:
{
show: false
}
};
return settings;
}
/**
* Generate GP data for each course
*/
private generateGPData()
{
let data: any = [];
this.courses.forEach(course =>
{
data.push(
{
value: [course.name, GPAUtils.getGP(course, course.letterGrade)],
itemStyle:
{
color: Constants.THEME.colors[data.length]
}
});
});
return data;
}
}
@@ -0,0 +1,17 @@
<template>
<div id="overall-bar">
<ve-bar height="450px" class="graph"
:extend="chartSettings"></ve-bar>
</div>
</template>
<script src="./overall-bar.ts" lang="ts"></script>
<style lang="scss" scoped>
#overall-bar
{
.graph
{
margin-top: 50px;
}
}
</style>
@@ -0,0 +1,149 @@
<template>
<div id="course-head" class="course-card-content main vertical-center">
<el-row>
<el-col :span="12" class="course-col-name">
<div v-if="clickable" class="course-name clickable" @click="redirect">{{course.name}}</div>
<div v-if="!clickable" class="course-name">{{course.name}}</div>
<div class="course-teacher">{{course.teacherName}}</div>
</el-col>
<el-col :span="12" 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" @click="redirect" :class="unread === 0 ? 'none' : 'unread'">
<span class="unread-number">{{unread}}</span>
<span class="unread-text" :class="clickable ? 'clickable' : ''">
new update{{unread >= 2 ? 's' : ''}}
</span>
</div>
</el-col>
</el-row>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import App, {Course} from '@/components/app/app';
import {CourseUtils} from '@/utils/course-utils';
@Component({
components: {}
})
export default class CourseHead extends Vue
{
// @ts-ignore
@Prop() unread: number;
// @ts-ignore
@Prop() course: Course;
// @ts-ignore
@Prop() clickable: boolean;
/**
* Redirect to the course page
*/
redirect()
{
if (!this.clickable) return;
App.instance.selectedTab = CourseUtils.formatTabIndex(this.course);
}
}
</script>
<style lang="scss">
// Main card content
.course-card-content.main
{
padding: 0 20px 0 20px;
height: 90px;
// Main color
background: white;
}
.course-col-name
{
// Align left
text-align: left;
float: left;
.course-name
{
overflow: hidden;
font-size: 22px;
color: var(--main);
}
.course-teacher
{
font-size: 12px;
color: #999999;
font-style: italic;
}
}
.course-col-grade
{
// Align right
text-align: right;
float: right;
// Adjust position
margin-top: -2px;
.course-grade
{
font-size: 21px;
}
.course-updates
{
font-size: 14px;
.unread-number
{
display: inline-block;
width: 20px;
text-align: center;
border-radius: 5px;
padding-left: 3px;
padding-right: 3px;
margin-right: 3px;
}
.unread-text
{
font-style: italic;
}
}
.course-updates.unread
{
.unread-number
{
background: var(--unread);
color: white;
}
.unread-text
{
color: var(--unread);
}
}
.course-updates.none
{
color: #999999;
.unread-number
{
background: #eeeeee;
}
}
}
</style>
@@ -0,0 +1,16 @@
// Card
.el-card.course-card
{
// Margins
margin-right: 20px;
margin-left: 20px;
// Height limit
max-height: 250px;
// Limit name length
white-space: nowrap;
// Expansion color
background: #f4f6f9;
}
@@ -0,0 +1,53 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
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';
import CourseHead from '@/pages/overall/overall-course/course-head/course-head.vue';
@Component({
components: {UnreadEntry, CourseHead}
})
export default class OverallCourse extends Vue
{
// @ts-ignore
@Prop({required: true}) course: Course;
private unread: number = -1;
private unreadAssignments: Assignment[] = [];
/**
* Count the number of unread assignments with cache
*/
countUnread(): number
{
if (this.unread == -1)
{
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)
}
})
}
}
@@ -0,0 +1,18 @@
<template>
<div id="overall-course">
<el-card class="course-card">
<course-head :clickable="true" :course="course" :unread="countUnread()"></course-head>
<div class="course-card-content expand"
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>
<script src="./overall-course.ts" lang="ts"></script>
<style src="./overall-course.scss" lang="scss" scoped></style>
@@ -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" scoped></style>
@@ -0,0 +1,180 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Course} from '@/components/app/app';
@Component({
})
export default class OverallLine extends Vue
{
// @ts-ignore
@Prop({required: true}) courses: Course[];
private settings =
{
// Title
title:
{
show: true,
textStyle:
{
fontSize: 12
},
text: 'Average Grade',
subtext: 'Average score trend for every course',
x: 'center'
},
// Legend
legend:
{
show: false,
//left: 'auto',
//align: 'left',
//orient: 'vertical'
textStyle:
{
fontSize: 11
},
icon: 'circle'
},
// Zoom bar
dataZoom:
[
// TODO: Calculate real value for startValue
{
startValue: '9/13/2019'
},
{
type: 'inside'
}
],
series:
{
smooth: true
},
xAxis:
{
//type: 'time'
},
yAxis:
{
min: (value: any) => Math.floor(value.min),
max: (value: any) => value.max
}
};
/**
* Convert assignments list to a graph dataset.
*/
get convertChart()
{
let courses = this.courses;
// Compute the column names
let columns = courses.map(course => course.name);
columns.unshift('date');
// Find the min date
let minDates = courses.map(course => new Date(course.assignments[course.assignments.length - 1].date).getTime());
let minDate: Date = new Date(Math.min.apply(null, minDates));
// Find the dates in between
let now = new Date();
let dates = [];
for (let date = minDate; date <= now; date.setDate(date.getDate() + 1))
{
dates.push(new Date(date));
}
// Compute the rows data
let rows: {[index: string]: any}[] = [];
dates.forEach(date =>
{
// Define row object
let row: {[index: string]:any} = {'date': date.toLocaleDateString('en-US')};
// Loop through courses
courses.forEach(course =>
{
// Total Mean
if (course.grading.method == 'TOTAL_MEAN')
{
let score = 0;
let max = 0;
// Loop through assignments
course.assignments.forEach(assignment =>
{
// If assignment should be displayed
if (assignment.complete != 'Complete') return;
// Date is being looked at
let assignmentDate = new Date(assignment.date);
if (assignmentDate.getTime() < date.getTime())
{
// Record scores
score += assignment.score;
max += assignment.scoreMax;
}
});
// Add average to the row
row[course.name] = score / max * 100;
}
else if (course.grading.method == 'PERCENT_TYPE')
{
let typeScores: {[index: string]: any} = {};
let typeCounts: {[index: string]: any} = {};
// Loop through assignments
course.assignments.forEach(assignment =>
{
// If assignment should be displayed
if (assignment.complete != 'Complete') return;
// Date is being looked at
let assignmentDate = new Date(assignment.date);
if (assignmentDate.getTime() < date.getTime())
{
// Record scores
if (typeScores[assignment.type] == undefined) typeScores[assignment.type] = 0;
typeScores[assignment.type] += assignment.score / assignment.scoreMax;
if (typeCounts[assignment.type] == undefined) typeCounts[assignment.type] = 0;
typeCounts[assignment.type] ++;
}
});
// Count total percentage (This is to avoid less than expected cases)
// Eg. If HW = 25% and Quiz = 75%, I have 1 hw and 0 quiz
// Without total percentage, the avg grade I get is 25%.
let totalPercentage = 0;
for (let type in course.grading.weightingMap)
{
if (typeScores[type] != undefined)
{
totalPercentage += course.grading.weightingMap[type];
}
}
// Count
let score = 0;
for (let type in typeScores)
{
let typeFactor = course.grading.weightingMap[type] / totalPercentage;
score += typeScores[type] * typeFactor / typeCounts[type];
}
// Add average to the row
if (score != 0) row[course.name] = score * 100;
}
});
// Add it to the array
rows.push(row);
});
return {
columns: columns,
rows: rows
}
}
}
@@ -0,0 +1,10 @@
<template>
<div id="overall-line">
<ve-line :data="convertChart" :extend="settings"></ve-line>
</div>
</template>
<script src="./overall-line.ts" lang="ts"></script>
<style lang="scss" scoped>
</style>
+8 -14
View File
@@ -1,17 +1,4 @@
// Add some margins
.el-card
{
margin: 10px;
height: 494px;
padding: 0;
// Vertical center
display: flex;
justify-content: center;
flex-direction: column;
}
.gpa-card
{
margin-left: 20px;
@@ -31,7 +18,7 @@
.gpa.text
{
font-size: 35px;
font-family: 'Avenir', Helvetica, Arial, sans-serif;
font-family: var(--font);
}
.gpa.max
@@ -46,3 +33,10 @@
{
font-size: 11px;
}
// Cards
.el-card.overall-bar-card
{
margin-right: 20px;
min-width: 170px;
}
+5 -136
View File
@@ -1,155 +1,24 @@
import {Component, Prop, Vue} from 'vue-property-decorator';
import GraphOverall from '@/pages/overall/graph-overall/graph-overall';
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: {GraphOverall}
components: {OverallLine, OverallBar, OverallCourse}
})
export default class Overall extends Vue
{
// @ts-ignore
@Prop({required: true}) courses: Course[];
/**
* Convert assignments list to a graph dataset.
*/
get convertCharts()
{
// Null case
if (this.courses == null) return [];
// Filter it
let courses: Course[] = this.filterCourses();
// Compute the column names
let columns = ['date'];
courses.forEach(course =>
{
columns.push(course.name);
});
// Find the min date
let minDate: Date = new Date();
courses.forEach(course =>
{
if (course.assignments.length == 0) return;
let date = new Date(course.assignments[course.assignments.length - 1].date);
if (date < minDate) minDate = date;
});
// Find the dates in between
let now = new Date();
let dates = [];
for (let date = minDate; date <= now; date.setDate(date.getDate() + 1))
{
dates.push(new Date(date));
}
// Initialize course specific variables
let courseScores: {[index: string]: any} = {};
let courseMaxScores: {[index: string]: any} = {};
let courseIndexes: {[index: string]: any} = {};
courses.forEach(course =>
{
courseScores[course.name] = 0;
courseMaxScores[course.name] = 0;
courseIndexes[course.name] = course.assignments.length - 1;
});
// Compute the rows data
let rows: {[index: string]: any}[] = [];
dates.forEach(date =>
{
// Define row object
let row: {[index: string]:any} = {'date': date.toLocaleDateString('en-US')};
// Loop through courses
courses.forEach(course =>
{
// Reversed loop through the assignments
for (let r = courseIndexes[course.name]; r >= 0; r--)
{
let assignment = course.assignments[r];
// If assignment should be displayed
if (assignment.complete != 'Complete') continue;
// Date is being looked at
let assignmentDate = new Date(assignment.date);
if (assignmentDate.getTime() == date.getTime())
{
// Record scores
courseScores[course.name] += assignment.score;
courseMaxScores[course.name] += assignment.scoreMax;
}
// Not now
else if (assignmentDate > date)
{
courseIndexes[course.name] = r;
break;
}
}
// Add average to the row
row[course.name] = courseScores[course.name] / courseMaxScores[course.name] * 100;
});
// Add it to the array
rows.push(row);
});
console.log(rows);
return {
columns: columns,
rows: rows
}
}
/**
* Return a list of courses that are graphed
*/
private filterCourses(): Course[]
{
// Define result
let result: Course[] = [];
// Filter through courses
this.courses.forEach(course =>
{
// Skip future or past courses
if (course.status != 'active') return;
// Skip courses without levels
if (course.level == 'None') return;
// Skip courses without assignments
if (course.assignments.length == 0) return;
// Add it to the list
result.push(course);
});
return result;
}
/**
* This function is called to get gpa since I can't import another
* class in the Vue file.
*/
public getGPA()
{
let gpa = GPAUtils.getGPA(this.courses);
// let result = '' + gpa.gpa;
/* Not accurate
if (!gpa.accurate)
{
result = `(${result})`;
}*/
return gpa;
return GPAUtils.getGPA(this.courses);
}
}
+15 -6
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>
@@ -13,15 +13,24 @@
</div>
</el-card>
</el-col>
<el-col :span="20">
<el-card style="margin-right: 20px">
<graph-overall :chart="convertCharts"></graph-overall>
<el-col :span="14">
<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="large overall-bar-card vertical-center">
<overall-bar :courses="courses"></overall-bar>
</el-card>
</el-col>
</el-row>
<div class=""></div>
<overall-course v-for="course in courses"
:course="course"
:key="course.id">
</overall-course>
</div>
</template>
<script src="./overall.ts" lang="ts"></script>
<style src="./overall.scss" lang="scss"></style>
<style src="./overall.scss" lang="scss" scoped></style>
+48
View File
@@ -0,0 +1,48 @@
import {Course} from '@/components/app/app';
export class CourseUtils
{
/**
* Return a list of courses that are graphed
*
* @param original Original course list
* @return Course[] Filtered course list
*/
public static getGradedCourses(original: Course[]): Course[]
{
// Define result
let result: Course[] = [];
// Filter through courses
original.forEach(course =>
{
// Skip future or past courses
if (course.status != 'active') return;
// Skip courses without levels
if (course.level == 'None') 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;
// Add it to the list
result.push(course);
});
return result;
}
/**
* Format course to tab index string
*
* @param course Course object
* @return string Tab index
*/
public static formatTabIndex(course: Course): string
{
return `course/${course.id}/${course.name.toLowerCase().split(' ').join('-')}`;
}
}
+18
View File
@@ -0,0 +1,18 @@
import moment from 'moment';
export class FormatUtils
{
/**
* Convert date format to yyyy-mm-dd
*
* @param _date Date
*/
public static toChartDate(_date: string | Date)
{
// Convert to Date
let date: Date = _date instanceof Date ? _date : new Date(_date);
// Convert to yyyy-mm-dd
return moment(date).format('YYYY-MM-DD');
}
}
+25
View File
@@ -102,4 +102,29 @@ export class GPAUtils
return -1;
}
/**
* Calculate the total-mean (total/max) average
*
* @param course Course
*/
public static getTotalMeanAverage(course: Course)
{
let score = 0;
let max = 0;
// Loop through assignments
course.assignments.forEach(assignment =>
{
// If assignment should be displayed
if (assignment.complete != 'Complete') return;
// Record scores
score += assignment.score;
max += assignment.scoreMax;
});
// Return
return score / max * 100;
}
}
-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
+9 -4
View File
@@ -1,4 +1,4 @@
import {Grade} from '@/components/app/app';
import {Assignment} from '@/components/app/app';
export default class JsonUtils
{
@@ -6,23 +6,28 @@ export default class JsonUtils
* This method filters the information provided in an assignments json.
*
* @param assignments Assignments object
* @returns Grade[] Filtered assignment grade object list
* @returns Assignment[] Filtered assignment grade object list
*/
public static filterAssignments(assignments: any): Grade[]
public static filterAssignments(assignments: any): Assignment[]
{
let result: Grade[] = [];
let result: Assignment[] = [];
assignments.assignments.forEach((assignment: any) =>
{
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,
include: assignment.include_in_calculated_grade == 1,
display: assignment.display_grade == 1,
unread: assignment.is_unread == 1,
scoreMax: assignment.maximum_score,
score: +assignment.raw_score
});
+41
View File
@@ -0,0 +1,41 @@
export default class VersionUtils
{
/**
* Compare two version numbers
*
* Eg.
* compare('0.1.2', '0.1.3') = -1
* compare('1.0.0', '0.1.3') = 1
* compare('0.0.1', '0.0.1') = 0
*
* @param ver1 Version 1
* @param ver2 Version 2
* @return number (-1 if ver1 < ver2), (1 if ver1 > ver2), (0 if equal)
*/
public static compare(ver1: string, ver2: string): number
{
// Equal case
if (ver1 == ver2) return 0;
// Split
let split1 = ver1.split('.');
let split2 = ver2.split('.');
// Detect each number
for (let i in split1)
{
// Get numbers
let num1 = split1[i];
let num2 = split2[i];
// Current number is equal
if (num1 == num2) continue;
// Current number is different
return +num1 < +num2 ? -1 : 1;
}
// Equal
return 0;
}
}