Skip to content

Display Statistics View per Student for their Submission Time#7222

Draft
bivanalhar wants to merge 24 commits intomasterfrom
bivan/course-stats-submission-time
Draft

Display Statistics View per Student for their Submission Time#7222
bivanalhar wants to merge 24 commits intomasterfrom
bivan/course-stats-submission-time

Conversation

@bivanalhar
Copy link
Copy Markdown
Contributor

@bivanalhar bivanalhar commented Mar 26, 2024

Feature

We implemented Submission Time Due Table, which basically shows the submission status for each published, non-submitted assessments for any particular student. The objective is to give tutors or teachers the overview of which assessments have not yet been done by the students, and how far it is from the due date.

This feature is requested as part of the effort in knowing which student needs some extra help in finishing up each assessment, and also to give tutors time to warn the students to finish up their assignments, preferably before the due date.

Overview

Since we want to focus on each student, the design, as well as the entry point, of this page is quite different from the other Course Statistics Page, as follows:

  • Firstly, you need to go to the Course Statistics Students page
  • Then, for the student that you might be interested in knowing their not-yet-submitted assessments, you can just click on their name, then the new tab will open, showing all those assessments
Screenshot 2024-04-18 at 5 37 25 PM

@bivanalhar bivanalhar force-pushed the bivan/course-stats-submission-time branch 2 times, most recently from 249dc8e to 7d4ad4c Compare March 26, 2024 05:41
@bivanalhar bivanalhar requested a review from ekowidianto March 27, 2024 05:22
- API merely sketch from FE (will complete implementation in BE)
- mock page for assessment statistics
- routes for assessments statistics fetching API
- at this point, only mock data is provided to FE from BE
- gather all info in BE, sending to FE
- code cleaning in BE
- using sortable and searchable table
- also fix the styling in concern files
- default of avg and stdev to 0 if assessment_id not found in hash
- include submitted also in counting attempting submissions
- use SQL to extract maximum grade
- already moved to index.tsx
- add Assessment Tab in index.tsx
- delete courseStatistics.js as already migrated to typescript
@bivanalhar bivanalhar force-pushed the bivan/course-stats-assessment branch from 34d2faf to 1c28e44 Compare April 17, 2024 10:14
@bivanalhar bivanalhar force-pushed the bivan/course-stats-submission-time branch from c813d8c to 6233460 Compare April 17, 2024 10:23
@bivanalhar bivanalhar marked this pull request as draft April 17, 2024 10:24
@bivanalhar bivanalhar removed the request for review from ekowidianto April 17, 2024 10:24
- it should match with the URL provided
@bivanalhar bivanalhar force-pushed the bivan/course-stats-assessment branch from 1c28e44 to 19f54cd Compare April 18, 2024 09:14
- API merely sketch from FE (will complete implementation in BE)
- mock page for assessment statistics
- routes for assessments statistics fetching API
- at this point, only mock data is provided to FE from BE
- gather all info in BE, sending to FE
- code cleaning in BE
- extend users API to include extract only students basic info
- prepare the Page for Submission Time (autocomplete field and space for table)
- needed for submission time table, to indicate the following
- if assessment has started respective to student's personal time
- depending on which student is chosen
- course_user_id constrained only within current course
- add test for submission time
- to display properly and show user if the timeline is personalised or not
- remove tab for submission time, entry through students stats table
- table design change to provide due date and due in
- include personalised indicator and real deadline
- change API routing for getting submission_time
@bivanalhar bivanalhar force-pushed the bivan/course-stats-submission-time branch from 6233460 to 0f1c5c7 Compare April 18, 2024 09:29
@bivanalhar bivanalhar force-pushed the bivan/course-stats-submission-time branch 2 times, most recently from a53a27b to da9d584 Compare April 19, 2024 01:50
@bivanalhar bivanalhar marked this pull request as ready for review April 19, 2024 01:54
@bivanalhar bivanalhar force-pushed the bivan/course-stats-submission-time branch 2 times, most recently from 3b1494c to 22d409d Compare April 19, 2024 03:00
format("%2d #{t('time.day')} %02d:%02d:%02d", days, hours, minutes, seconds)
end

def time_until_due(submitted_at, end_at)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function behaves as time_delta between datetimestamp1 and datetimestamp2, it shouldn't be specific to time_until_due.
Also I don't think it makes sense for end_at - expected submission_time to represent "time until due".

Can we change this to be a time_delta instead? Or consider not having a function for this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think time_delta is a very general phrase, even though what this function represents is actually how far the submitted_at is from the end_at.

The usage of time_until_due might be communicating the ideas better to the developer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point was that time_until_due(submitted_at, end_at) is behaving as a general function, time delta represents how far datetimestamp1 (submitted_at) is from datetimestamp2 (end_at).

time_until_due function signature sounds like time_until_due(assessment_id, student_id) which reports the time until the assessment is due for the given student (default time if no student is provided, or no personal times).

@ekowidianto your thoughts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed into calculate_time_interval and also the arguments naming is revised to from and optional_to

json.workflowState 'unstarted'
end

json.dueIn time_until_due(Time.now, end_at)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would Time.now - end_at be sufficient?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be sufficient but I'm afraid the code's not communicative enough (right now it's just using Time.now since we are not considering the submitted/graded/published submissions).

But for the future, if we want to consider those kinds of submissions as well, the function time_until_due might be more general and can be used for that case as well.

Comment thread app/views/course/statistics/aggregate/submission_due.json.jbuilder Outdated
json.name @all_students.first.name

json.assessments @assessments do |assessment|
student_id = @all_students.first.id
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we computing student_id inside the do-loop?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh ya sorry about this. this can be put also outside the do-loop, and might be saving the execution time a bit.

Even though the effect might not be significant, but I moved this out from the loop

end

def submission_due
@all_students = [CourseUser.where(id: params[:student_id]).first]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is @all_students only capturing one student?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is because this submission_due API only accept one student_id from the frontend (the way this API is called is firstly to specify which student we would like to know more).

And the reason I'm using @all_students here is because my intention is to reuse the function all_submissions_info

fetch_all_assessment_related_statistics_hash
end

def submission_due
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

submissions_due instead of submission_due? Since we expect multiple submissions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking that submission_due is also correct since we only expect 1 submission per assessment.
Nevertheless, I can change this into what you suggested as well

Comment on lines +29 to +31
Safe: 'safe' as const,
AlmostLate: 'almostLate' as const,
Overdue: 'overdue' as const,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NotDue, AlmostDue, OverDue.
^ just a suggestion. Keeping the "xxxDue" convention (two words) makes it easier for developers to remember.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You got the point there, alright I'll change it.


let dueStates = '';

if (days >= 3 && rawTime >= 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go into constants file, perhaps AlmostDueThreshold or something similar, instead of here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. I've changed this

Comment on lines 19 to 31
personal_times AS (
SELECT cu.id AS course_user_id, pt.end_at, pt.assessment_id
SELECT cu.id AS course_user_id, pt.start_at, pt.end_at, pt.fixed, pt.assessment_id
FROM (
SELECT course_users.id
FROM course_users
WHERE course_users.course_id = #{course_id}
) cu
LEFT JOIN (
SELECT course_user_id, end_at, assessment_id
SELECT course_user_id, start_at, end_at, fixed, assessment_id
FROM course_user_personal_end_at
) pt
ON cu.id = pt.course_user_id
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why need nested subquery?
Can we do:

personal_times AS (
  SELECT cu.id AS course_user_id, pt.start_at, pt.end_at, pt.fixed, pt.assessment_id
  FROM course_users cu
  LEFT JOIN course_user_personal_end_at pt
  ON cu.id = pt.course_user_id
  WHERE cu.course_id = #{course_id}
)```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for the other queries

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when making this nested subquery, my consideration is to make the code neater to read (having the code just like how u wrote it looks very condensed and not really that nice to read).

However, I think this is just about preference and I have adjusted the code to be like what you suggested above

Comment on lines +92 to +93
_, end_at, = @personal_timeline_hash[[@assessment.id, submitter_course_user.id]] ||
@reference_times_hash[@assessment.id]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this account for Multiple Reference Timelines (as in the timeline designer)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this functionality considers the personalised timeline to be the priority, then only using reference timeline if there's no personalised one

@bivanalhar bivanalhar force-pushed the bivan/course-stats-submission-time branch from 22d409d to 22a3868 Compare April 19, 2024 03:23
Comment on lines +262 to +272
expected_end_at = published_assessment.end_at.change(usec: published_assessment.end_at.usec / 1000 * 1000)
parsed_end_at = DateTime.parse(json_result['assessments'][0]['endAt']).
change(usec: DateTime.parse(json_result['assessments'][0]['endAt']).
usec / 1000 * 1000)
parsed_reference_end_at = DateTime.parse(json_result['assessments'][0]['referenceEndAt']).
change(usec: DateTime.parse(json_result['assessments'][0]['referenceEndAt']).
usec / 1000 * 1000)

expect(json_result['assessments'][0]['workflowState']).to eq('attempting')
expect(parsed_end_at).to eq(expected_end_at)
expect(parsed_reference_end_at).to eq(expected_end_at)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't there a .to be_within(time_delta) method that we can use instead of doing truncation like this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right. I have done some more inspection and indeed, previously I was using this be_within function but I was doing it wrongly and thus it's unsuccessful

now that I have done it properly, it gets right now

# This is named aggregate controller as naming this as course controller leads to name conflict issues
class Course::Statistics::AggregateController < Course::Statistics::Controller
before_action :preload_levels, only: [:all_students, :course_performance]
before_action :fetch_published_assessments, only: [:all_assessments, :submission_due]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
before_action :fetch_published_assessments, only: [:all_assessments, :submission_due]
before_action :preload_assessments, only: [:all_assessments, :submission_due]

be consistent in the naming. see line 4 above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it.. though I will change it into preload_published_assessments since we actually only care about the published one, and ignoring the unpublished.

- simplify SQL script not to use redundant nesting code
- submission_due -> submissions_due
- fetch -> preload to make it consistent with other similar functions
- naming of dueInStates to be more consistent (notDue, almostDue, overDue)
- student name in student stats link to user page
- add one column for clickable icon, link to overdue assessments
@bivanalhar bivanalhar force-pushed the bivan/course-stats-assessment branch 8 times, most recently from a95ee0c to 4226179 Compare August 7, 2024 04:06
@bivanalhar bivanalhar force-pushed the bivan/course-stats-assessment branch 3 times, most recently from 13d478b to aa23e0c Compare September 9, 2024 22:58
@cysjonathan cysjonathan force-pushed the bivan/course-stats-assessment branch from aa23e0c to 62e2ebf Compare September 12, 2024 04:52
Base automatically changed from bivan/course-stats-assessment to master September 12, 2024 06:08
@cysjonathan cysjonathan marked this pull request as draft October 28, 2024 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants