8000 Yuqiang/student dashboard loading issue by smallst · Pull Request #8016 · codecombat/codecombat · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Yuqiang/student dashboard loading issue #8016

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/core/store/modules/courseInstances.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export default {
courseID: course._id,
classroomID: classroom._id,
ownerID: classroom.ownerID,
aceConfig: {}
aceConfig: {},
})
courseInstance.notyErrors = false

Expand Down
109 changes: 58 additions & 51 deletions app/templates/courses/courses-view.pug
Original file line number Diff line number Diff line change
Expand Up @@ -177,21 +177,14 @@ mixin classrooms_content()
// internal play-test course which we removed later
if !course || course._id === '5eb34fc8dc0fd35e8eae66b0'
- continue;
- var stats = classroom.statsForSessions(courseInstance.sessions, course._id);
- var nextLevel = stats.levels.next;
- var isCourseLocked = classroom.isStudentOnLockedCourse(me.get('_id'), courseID)
- allCoursesComplete = allCoursesComplete && stats.courseComplete
if nextLevel
- var isNextLevelLocked = classroom.isStudentOnLockedLevel(me.get('_id'), courseID, nextLevel.get('original'))
- var isLocked = nextLevel === undefined ? isCourseLocked : isNextLevelLocked
- var mapUrl = view.urls.courseWorldMap({courseId: courseID, courseInstanceId: courseInstance.get('_id'), campaignPage: nextLevel.get('campaignPage'), campaignId: course.campaignID, classroomId: courseInstance.get('classroomID')});

if course
- var courseUrl = view.urls.courseWorldMap({ course, courseInstance })
h6
span.spr= i18n(course, 'name')
small
if courseInstance.get('courseID') !== view.utils.courseIDs.HACKSTACK
a.view-levels-btn(data-href=mapUrl, data-course-id=courseInstance.get('courseID'), data-courseinstance-id=courseInstance.id, data-i18n="courses.view_map")
a.view-levels-btn(data-href=courseUrl, data-course-id=courseInstance.get('courseID'), data-courseinstance-id=courseInstance.id, data-i18n="courses.view_map")
if view.courseInstanceHasProject(courseInstance)
a.view-project-gallery-link(data-course-id=courseInstance.get('courseID'), data-courseinstance-id=courseInstance.id, data-i18n="courses.view_project_gallery")
if view.utils.isCodeCombat && classroom.hasAssessments({courseId: course._id})
Expand All @@ -200,17 +193,30 @@ mixin classrooms_content()
if view.showVideosLinkForCourse(course._id)
= " "
a.view-videos-link(data-classroom-id=classroom.id, data-i18n="courses.view_videos", data-course-id=course._id, data-course-name=i18n(course, 'name'))
if courseInstance.get('courseID') === view.utils.allCourseIDs.HACKSTACK
- var hackstackUrl = view.urls.courseWorldMap({courseId: courseID, courseInstanceId: courseInstance.get('_id')})
.pull-right
a.btn.btn-navy.btn-lg.m-b-1(href=hackstackUrl data-event-action="Students Start HackStack Course")
span(data-i18n="courses.start")
else
if view.utils.isCodeCombat
+course-instance-body(courseInstance, classroom)
else
+course-instance-body(courseInstance, classroom, stats, nextLevel, mapUrl, course.campaignID, isLocked)
.clearfix
if courseInstance.get('courseID') === view.utils.allCourseIDs.HACKSTACK
- var hackstackUrl = view.urls.courseWorldMap({courseId: courseID, courseInstanceId: courseInstance.get('_id')})
.pull-right
a.btn.btn-navy.btn-lg.m-b-1(href=hackstackUrl data-event-action="Students Start HackStack Course")
span(data-i18n="courses.start")
else if courseInstance.sessions
- var stats = classroom.statsForSessions(courseInstance.sessions, course._id);
- var nextLevel = stats.levels.next;
- var isCourseLocked = classroom.isStudentOnLockedCourse(me.get('_id'), courseID)
- allCoursesComplete = allCoursesComplete && stats.courseComplete
if nextLevel
- var isNextLevelLocked = classroom.isStudentOnLockedLevel(me.get('_id'), courseID, nextLevel.get('original'))
- var isLocked = nextLevel === undefined ? isCourseLocked : isNextLevelLocked
- var mapUrl = view.urls.courseWorldMap({courseId: courseID, courseInstanceId: courseInstance.get('_id'), campaignPage: nextLevel.get('campaignPage'), campaignId: course.campaignID, classroomId: courseInstance.get('classroomID')});
if view.utils.isCodeCombat
+course-instance-body(courseInstance, classroom)
else
+course-instance-body(courseInstance, classroom, stats, nextLevel, mapUrl, course.campaignID, isLocked)
else
.pull-right
a.btn.btn-navy.btn-lg.m-b-1(href=courseUrl data-event-action="Students Start Course")
span(data-i18n="courses.start")

.clearfix
- var classroomCourseIds = classroom.get('courses').map(i=>i._id).sort().join()
- var courseInstancesCourseIds = courseInstances.map(i=>i.get('courseID')).sort().join()
- var allCoursesPlayed = classroomCourseIds === courseInstancesCourseIds
Expand Down Expand Up @@ -296,37 +302,38 @@ mixin coco_main_content()
hr

- var nextLevelLocked = view.nextLevelInfo && view.nextLevelInfo.locked
a.play-next-level-btn.tile(disabled=!view.nextLevelInfo || nextLevelLocked, data-i18n=nextLevelLocked ? '[title]courses.ask_teacher_to_unlock_instructions' : '[title]courses.play_next_level' class=view.hasOnlyCodeNinjasEsportsCamps() ? 'hidden' : '')
- var levelInfo = view.nextLevelInfo || {}
- var level = levelInfo.level
- var levelName = ''
- var levelWithI18n = level ? view.originalLevelMap[level.get('original')] : null
- if (levelWithI18n)
- levelName = i18n(levelWithI18n.attributes, 'name')
- else if (level)
- levelName = level.get('name')
- if (levelInfo.number && levelInfo.number > 0)
- // Prepend level number, like "Level 1: Dungeons of Kithgard"
- levelName = $.i18n.t('play_level.level') + ' ' + levelInfo.number + ': ' + levelName
- else if (levelInfo.number)
- // Prepend level type and name, like "Concept Challenge: Long Steps"
- levelName = levelInfo.number + ': ' + levelName
- if (levelInfo.courseAcronym)
- // Prepend course acronym, like "CS1 Level 1: Dungeons of Kithgard"
- levelName = levelInfo.courseAcronym + ' ' + levelName
- var levelImage = view.nextLevelImage()
img(src=levelImage, alt=levelName, class="level-image" + (levelImage ? "" : " placeholder"))
h3.dynamic-level-name.overlay-text= levelName + (nextLevelLocked ? " (locked)" : "")
.tile-text-backdrop
.stats-text-container
.overlay-text.stats-text
span(data-i18n='courses.levels_completed', data-i18n-options={count: me.get('stats') ? me.get('stats').gamesCompleted || 0 : 0})
.play-text-container
.overlay-text.play-text
if nextLevelLocked
span(data-i18n="courses.ask_teacher_to_unlock")
else
span(data-i18n="courses.play_next_level")
if view.nextLevelInfo
a.play-next-level-btn.tile(disabled=nextLevelLocked, data-i18n=nextLevelLocked ? '[title]courses.ask_teacher_to_unlock_instructions' : '[title]courses.play_next_level' class=view.hasOnlyCodeNinjasEsportsCamps() ? 'hidden' : '')
- var levelInfo = view.nextLevelInfo || {} 10000
- var level = levelInfo.level
- var levelName = ''
- var levelWithI18n = level ? view.originalLevelMap[level.get('original')] : null
- if (levelWithI18n)
- levelName = i18n(levelWithI18n.attributes, 'name')
- else if (level)
- levelName = level.get('name')
- if (levelInfo.number && levelInfo.number > 0)
- // Prepend level number, like "Level 1: Dungeons of Kithgard"
- levelName = $.i18n.t('play_level.level') + ' ' + levelInfo.number + ': ' + levelName
- else if (levelInfo.number)
- // Prepend level type and name, like "Concept Challenge: Long Steps"
- levelName = levelInfo.number + ': ' + levelName
- if (levelInfo.courseAcronym)
- // Prepend course acronym, like "CS1 Level 1: Dungeons of Kithgard"
- levelName = levelInfo.courseAcronym + ' ' + levelName
- var levelImage = view.nextLevelImage()
img(src=levelImage, alt=levelName, class="level-image" + (levelImage ? "" : " placeholder"))
h3.dynamic-level-name.overlay-text= levelName + (nextLevelLocked ? " (locked)" : "")
.tile-text-backdrop
.stats-text-container
.overlay-text.stats-text
span(data-i18n='courses.levels_completed', data-i18n-options={count: me.get('stats') ? me.get('stats').gamesCompleted || 0 : 0})
.play-text-container
.overlay-text.play-text
if nextLevelLocked
span(data-i18n="courses.ask_teacher_to_unlock")
else
span(data-i18n="courses.play_next_level")

- tiles = view.aiLeagueTiles()
if tiles.length
Expand Down
70 changes: 56 additions & 14 deletions app/views/courses/CoursesView.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,14 @@ module.exports = (CoursesView = (function () {
this.utils = utils
this.classCodeQueryVar = utils.getQueryVariable('_cc', false)
this.courseInstances = new CocoCollection([], { url: `/db/user/${me.id}/course-instances`, model: CourseInstance })

this.classroomsLoaded = false
this.courseInstancesLoaded = false
this.courseInstances.comparator = ci => parseInt(ci.get('classroomID').substr(0, 8), 16) + utils.orderedCourseIDs.indexOf(ci.get('courseID'))
this.listenToOnce(this.courseInstances, 'sync', this.onCourseInstancesLoaded)
this.listenToOnce(this.courseInstances, 'sync', function () {
this.courseInstancesLoaded = true
this.onCourseInstancesLoaded()
})
this.supermodel.loadCollection(this.courseInstances, { cache: false })
this.classrooms = new CocoCollection([], { url: '/db/classroom', model: Classroom })
this.classrooms.comparator = (a, b) => b.id.localeCompare(a.id)
Expand All @@ -116,8 +122,10 @@ module.exports = (CoursesView = (function () {
}
this.supermodel.addPromiseResource(store.dispatch('levelSessions/fetchLevelSessionsForCampaign', { campaignHandle: campaign, options: { data: sessionFetchOptions } }))
this.campaignLevels = new Levels()
return this.supermodel.trackRequest(this.campaignLevels.fetchForCampaign(this.hourOfCodeOptions.campaignId, { data: { project: `original,primerLanguage,slug,i18n.${me.get('preferredLanguage', true)}` } }))
this.supermodel.trackRequest(this.campaignLevels.fetchForCampaign(this.hourOfCodeOptions.campaignId, { data: { project: `original,primerLanguage,slug,i18n.${me.get('preferredLanguage', true)}` } }))
}
this.classroomsLoaded = true
this.onCourseInstancesLoaded()
})
this.store = store
this.originalLevelMap = {}
Expand Down Expand Up @@ -338,22 +346,53 @@ module.exports = (CoursesView = (function () {
}

onCourseInstancesLoaded () {
if (!this.classroomsLoaded || !this.courseInstancesLoaded) return
// HoC 2015 used special single player course instances
this.courseInstances.remove(this.courseInstances.where({ hourOfCode: true }))
const classroomLanguagesMap = {}
this.classrooms.forEach(cls => {
classroomLanguagesMap[cls.id.toString()] = cls.get('aceConfig').language
})

return (() => {
const result = []
const fetchSessions = (instance) => {
const fetchOptions = { data: { project: 'state.complete,level.original,playtime,changed' } }
const collection = new CocoCollection([], {
url: instance.url() + '/course-level-sessions/' + me.id,
model: LevelSession,
})
collection.comparator = 'changed'
collection.fetch(fetchOptions)
return collection
}
const dynamicLoadLanguageSessions = () => {
// classrooms has same language shares progress, so we only need to fetch session once
const languageSessions = { others: {} }
for (const courseInstance of Array.from(this.courseInstances.models)) {
if (!courseInstance.get('classroomID')) { continue }
courseInstance.sessions = new CocoCollection([], {
url: courseInstance.url() + '/course-level-sessions/' + me.id,
model: LevelSession
})
courseInstance.sessions.comparator = 'changed'
result.push(this.supermodel.loadCollection(courseInstance.sessions, { data: { project: 'state.complete,level.original,playtime,changed' } }))
const courseID = courseInstance.get('courseID')
// 99.9% courseInstances has aceConfig
const lang = classroomLanguagesMap[courseInstance.get('classroomID').toString()]
if (!(lang in languageSessions)) {
languageSessions[lang] = {}
}
if (!(courseID in languageSessions[lang])) {
languageSessions[lang][courseID] = []
}
languageSessions[lang][courseID].push(courseInstance)
}
return result
})()
for (const lang in languageSessions) {
const instancesByCourse = languageSessions[lang]
for (const courseID in instancesByCourse) {
const instances = instancesByCourse[courseID]
// only fetch first course-instances
const collection = fetchSessions(instances[0])
for (const instance of instances) {
instance.sessions = collection
}
}
}
}
dynamicLoadLanguageSessions()
this.renderSelectors('.course-instance-entry')
}

onLoaded () {
Expand Down Expand Up @@ -416,6 +455,9 @@ module.exports = (CoursesView = (function () {
this.allCompleted = !_.some(this.classrooms.models, function (classroom) {
return _.some(this.courseInstances.where({ classroomID: classroom.id }), function (courseInstance) {
const course = this.store.state.courses.byId[courseInstance.get('courseID')]
if (!courseInstance.sessions) {
return false
}
const stats = classroom.statsForSessions(courseInstance.sessions, course._id)
if (stats.levels != null ? stats.levels.next : undefined) {
// This could be made smarter than just picking the next level from the first incomplete course
Expand Down Expand Up @@ -458,7 +500,7 @@ module.exports = (CoursesView = (function () {
this.listenTo(levels, 'sync', () => {
if (this.destroyed) { return }
for (const level of Array.from(levels.models)) { this.originalLevelMap[level.get('original')] = level }
return this.render()
this.renderSelectors('.course-instance-entry')
})
return this.supermodel.trackRequest(levels.fetchForClassroom(classroomID, { data: { project: `original,primerLanguage,slug,name,i18n.${me.get('preferredLanguage', true)},displayName` } }))
}
Expand Down
2 changes: 1 addition & 1 deletion app/views/courses/TeacherClassView.js
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ module.exports = (TeacherClassView = (function () {
courseID,
classroomID: this.classroom.id,
ownerID: this.classroom.get('ownerID'),
aceConfig: {}
aceConfig: {},
})
courseInstance.notyErrors = false // handling manually
this.courseInstances.add(courseInstance)
Expand Down
2 changes: 1 addition & 1 deletion app/views/courses/TeacherClassesView.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ module.exports = (TeacherClassesView = (function () {
if (!courseInstance) {
courseInstance = new CourseInstance({
classroomID: classroom.id,
courseID: course.id
courseID: course.id,
})
// TODO: figure out a better way to get around triggering validation errors for properties
// that the server will end up filling in, like an empty members array, ownerID
Expand Down
0