Compare commits

..

51 Commits

Author SHA1 Message Date
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
15 changed files with 90 additions and 24 deletions
+10
View File
@@ -25,4 +25,14 @@
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <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> <script src="https://unpkg.com/element-ui/lib/index.js"></script>
</body> </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> </html>
+8
View File
@@ -7,6 +7,14 @@
color: #2c3e50; color: #2c3e50;
} }
#app-content
{
// Limit max width
max-width: 1300px;
text-align: center;
margin: auto;
}
.theme-default .theme-default
{ {
--unread: #ff6c00; --unread: #ff6c00;
+6 -5
View File
@@ -15,6 +15,7 @@ import {GPAUtils} from '@/utils/gpa-utils';
export interface Assignment export interface Assignment
{ {
id: number, id: number,
scoreId: number,
type: string, type: string,
typeId: number, typeId: number,
description: string, description: string,
@@ -79,7 +80,7 @@ export default class App extends Vue
public token: string = ''; public token: string = '';
// Http Client // Http Client
public http: HttpUtils = new HttpUtils(''); public static http: HttpUtils = new HttpUtils();
/** /**
* This is called when the instance is created. * This is called when the instance is created.
@@ -104,7 +105,7 @@ export default class App extends Vue
this.token = token; this.token = token;
// Assign token to http client // Assign token to http client
this.http.token = token; App.http.token = token;
// Load data // Load data
this.loadCoursesAfterLogin(); this.loadCoursesAfterLogin();
@@ -115,7 +116,7 @@ export default class App extends Vue
*/ */
public loadCoursesAfterLogin() public loadCoursesAfterLogin()
{ {
this.http.post('/courses', {}).then(response => App.http.post('/courses', {}).then(response =>
{ {
// Check success // Check success
if (response.success) if (response.success)
@@ -144,7 +145,7 @@ export default class App extends Vue
this.courses.forEach(course => this.courses.forEach(course =>
{ {
// Send request to get assignments // 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 // Check success
if (response.success) if (response.success)
@@ -204,7 +205,7 @@ export default class App extends Vue
else else
{ {
// Request grading scheme for this course // 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 // Check success
if (response.success) if (response.success)
+1 -1
View File
@@ -1,6 +1,6 @@
<template> <template>
<div id="app" class="theme-default"> <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" <navigation :courses="filteredCourses"
v-on:sign-out="signOut()" v-on:sign-out="signOut()"
v-on:navigation:select="onNavigate"> v-on:navigation:select="onNavigate">
+10 -4
View File
@@ -1,6 +1,7 @@
import {Component, Prop, Vue} from 'vue-property-decorator'; import {Component, Prop, Vue} from 'vue-property-decorator';
import Constants from '@/constants'; import Constants from '@/constants';
import {HttpUtils} from '@/utils/http-utils'; import {HttpUtils} from '@/utils/http-utils';
import App from '@/components/app/app';
/** /**
* This component handles user login, and obtains data from the server. * 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 loading: boolean = false;
public error: String = ''; public error: String = '';
@Prop()
public http?: HttpUtils;
/** /**
* This is called when the instance is created. * This is called when the instance is created.
*/ */
public 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 // Check login cookies
if (this.$cookies.isKey('va.token')) if (this.$cookies.isKey('va.token'))
{ {
@@ -42,7 +47,7 @@ export default class Login extends Vue
this.loading = true; this.loading = true;
// Fetch request // 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 => .then(response =>
{ {
// Check success // Check success
@@ -50,6 +55,7 @@ export default class Login extends Vue
{ {
// Save token to cookies // Save token to cookies
this.$cookies.set('va.token', response.data, '7d'); this.$cookies.set('va.token', response.data, '7d');
this.$cookies.set('va.version', Constants.VERSION);
// Call custom event with token // Call custom event with token
this.$emit('login:token', response.data); 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 API_URL: string = 'https://va.hydev.org/api';
public static VERSION: string = '0.3.2.452'; public static VERSION: string = '0.3.3.502';
public static GITHUB: string = 'https://github.com/HyDevelop/VeracrossAnalyzer.Client'; public static GITHUB: string = 'https://github.com/HyDevelop/VeracrossAnalyzer.Client';
@@ -12,7 +12,7 @@
white-space: nowrap; white-space: nowrap;
// Expansion color // Expansion color
background: #f9f9f9; background: #f4f6f9;
// Main card content // Main card content
.course-card-content.main .course-card-content.main
@@ -1,5 +1,5 @@
import {Component, Prop, Vue} from 'vue-property-decorator'; import {Component, Prop, Vue} from 'vue-property-decorator';
import {Assignment, Course} from '@/components/app/app'; import App, {Assignment, Course} from '@/components/app/app';
import {GPAUtils} from '@/utils/gpa-utils'; import {GPAUtils} from '@/utils/gpa-utils';
import Constants from '@/constants'; import Constants from '@/constants';
import UnreadEntry from '@/pages/overall/overall-course/unread-entry/unread-entry'; import UnreadEntry from '@/pages/overall/overall-course/unread-entry/unread-entry';
@@ -28,8 +28,25 @@ export default class OverallCourse extends Vue
else return this.unread; else return this.unread;
} }
unreadTable() /**
* Mark an assignment as read
*/
markAsRead(assignment: Assignment)
{ {
return [{date: '2019-10-04', name: 'Letter from a Penn Farmer Discussion Forum', grade: '14|14'}]; 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)
}
})
} }
} }
@@ -35,7 +35,8 @@
v-if="countUnread() !== 0"> v-if="countUnread() !== 0">
<unread-entry v-for="assignment in unreadAssignments" <unread-entry v-for="assignment in unreadAssignments"
:assignment="assignment" :assignment="assignment"
:key="assignment.id"> :key="assignment.id"
v-on:mark-as-read="markAsRead">
</unread-entry> </unread-entry>
</div> </div>
</el-card> </el-card>
@@ -3,7 +3,7 @@
.unread-entry .unread-entry
{ {
height: 40px; height: 40px;
padding: 0 20px 0 20px; padding: 0 10px 0 20px;
background: #f5f7fa; background: #f5f7fa;
text-align: left; text-align: left;
@@ -11,6 +11,8 @@
// Date // Date
.el-col.date .el-col.date
{ {
min-width: 130px;
span.month span.month
{ {
margin-right: 5px; margin-right: 5px;
@@ -23,8 +25,11 @@
} }
} }
// Description
.el-col.description .el-col.description
{ {
width: unset;
span.type span.type
{ {
display: inline-block; display: inline-block;
@@ -46,6 +51,7 @@
.el-col.grade .el-col.grade
{ {
text-align: right; text-align: right;
float: right;
span.percent span.percent
{ {
@@ -74,6 +80,14 @@
background: #ddd; background: #ddd;
color: #333; color: #333;
} }
// Mark as read
button.mark-as-read
{
margin-left: 8px;
color: #aaa;
padding: 4px;
}
} }
.entry-box .entry-box
@@ -14,8 +14,17 @@ export default class UnreadEntry extends Vue
* *
* @param date Date * @param date Date
*/ */
private getMoment(date: string) getMoment(date: string)
{ {
return moment(new Date(date)); return moment(new Date(date));
} }
/**
* Mark this unread assignment as read
*/
markAsRead()
{
// Call custom event
this.$emit('mark-as-read', this.assignment)
}
} }
@@ -19,6 +19,9 @@
</span> </span>
<span class="score entry-box">{{assignment.score}}</span> <span class="score entry-box">{{assignment.score}}</span>
<span class="max entry-box">{{assignment.scoreMax}}</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-col>
</el-row> </el-row>
</div> </div>
@@ -56,7 +56,8 @@ export default class OverallLine extends Vue
}, },
yAxis: yAxis:
{ {
min: (value: any) => value.min - 10 min: (value: any) => value.min,
max: (value: any) => value.max
} }
}; };
-5
View File
@@ -4,11 +4,6 @@ export class HttpUtils
{ {
public token: string = ''; public token: string = '';
constructor (token: string)
{
this.token = token;
}
public post(node: string, body: any): Promise<any> public post(node: string, body: any): Promise<any>
{ {
// Add token // Add token
+1
View File
@@ -17,6 +17,7 @@ export default class JsonUtils
result.push( result.push(
{ {
id: assignment.assignment_id, id: assignment.assignment_id,
scoreId: assignment.score_id,
type: assignment.assignment_type, type: assignment.assignment_type,
typeId: assignment.assignment_type_id, typeId: assignment.assignment_type_id,
description: assignment.assignment_description, description: assignment.assignment_description,