Skip to content

Commit ba4b33b

Browse files
committed
Add contests state and actions to leaderboard management.
Added top X for contest Leaderboard (create course dropdown and course admin panel) Added Top X for assessment workspace contest leaderboard and fixed export contest leaderboard (assessment workspace) Fixed Leaderboard dropdown to show only published contests and omit voting assessments.
1 parent 75ec8a1 commit ba4b33b

File tree

17 files changed

+117
-39
lines changed

17 files changed

+117
-39
lines changed

src/commons/application/ApplicationTypes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ export const defaultLeaderboard: LeaderboardState = {
353353
userXp: [],
354354
contestScore: [],
355355
contestPopularVote: [],
356-
code: 'Initial code'
356+
code: 'Initial code',
357+
contests: []
357358
};
358359

359360
const getDefaultLanguageConfig = (): SALanguage => {

src/commons/application/types/SessionTypes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export type SessionState = {
4242
readonly enableOverallLeaderboard?: boolean;
4343
readonly enableContestLeaderboard?: boolean;
4444
readonly topLeaderboardDisplay?: number;
45+
readonly topContestLeaderboardDisplay?: number;
4546
readonly sourceChapter?: Chapter;
4647
readonly sourceVariant?: Variant;
4748
readonly moduleHelpText?: string;
@@ -111,6 +112,7 @@ export type CourseConfiguration = {
111112
enableOverallLeaderboard: boolean;
112113
enableContestLeaderboard: boolean;
113114
topLeaderboardDisplay: number;
115+
topContestLeaderboardDisplay: number;
114116
sourceChapter: Chapter;
115117
sourceVariant: Variant;
116118
moduleHelpText: string;

src/commons/dropdown/DropdownCreateCourse.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const DropdownCreateCourse: React.FC<Props> = props => {
4343
enableOverallLeaderboard: true,
4444
enableContestLeaderboard: true,
4545
topLeaderboardDisplay: 100,
46+
topContestLeaderboardDisplay: 10,
4647
sourceChapter: Chapter.SOURCE_1,
4748
sourceVariant: Variant.DEFAULT,
4849
moduleHelpText: ''
@@ -279,6 +280,24 @@ const DropdownCreateCourse: React.FC<Props> = props => {
279280
/>
280281
</FormGroup>
281282
</div>
283+
<div>
284+
<FormGroup
285+
label="Contest Leaderboard Top XX Display"
286+
labelInfo="(configurable later on)"
287+
labelFor="contest-leaderboard-top-display"
288+
>
289+
<InputGroup
290+
id="topContestLeaderboardDisplay"
291+
value={String(courseConfig.topContestLeaderboardDisplay)}
292+
onChange={e =>
293+
setCourseConfig({
294+
...courseConfig,
295+
topContestLeaderboardDisplay: Number(e.target.value)
296+
})
297+
}
298+
/>
299+
</FormGroup>
300+
</div>
282301
<div>
283302
<FormGroup
284303
label="Default Source Chapter"

src/commons/mocks/UserMocks.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ export const mockCourseConfigurations: CourseConfiguration[] = [
376376
enableOverallLeaderboard: true,
377377
enableContestLeaderboard: true,
378378
topLeaderboardDisplay: 100,
379+
topContestLeaderboardDisplay: 10,
379380
sourceChapter: Chapter.SOURCE_1,
380381
sourceVariant: Variant.DEFAULT,
381382
moduleHelpText: '',
@@ -392,6 +393,7 @@ export const mockCourseConfigurations: CourseConfiguration[] = [
392393
enableOverallLeaderboard: true,
393394
enableContestLeaderboard: true,
394395
topLeaderboardDisplay: 100,
396+
topContestLeaderboardDisplay: 10,
395397
sourceChapter: Chapter.SOURCE_2,
396398
sourceVariant: Variant.DEFAULT,
397399
moduleHelpText: 'Help Text!',

src/commons/sagas/LeaderboardSaga.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { selectTokens } from './BackendSaga';
88
import {
99
getAllTotalXp,
1010
getContestPopularVoteLeaderboard,
11-
getContestScoreLeaderboard
11+
getContestScoreLeaderboard,
12+
getAllContests
1213
} from './RequestsSaga';
1314

1415
const LeaderboardSaga = combineSagaHandlers(LeaderboardActions, {
@@ -41,7 +42,18 @@ const LeaderboardSaga = combineSagaHandlers(LeaderboardActions, {
4142
if (contestPopularVotes) {
4243
yield put(actions.saveAllContestPopularVotes(contestPopularVotes));
4344
}
44-
}
45+
},
46+
47+
getContests: function* () {
48+
const tokens: Tokens = yield selectTokens();
49+
50+
const contests = yield call(getAllContests, tokens);
51+
console.log(contests, 'rows');
52+
53+
if (contests) {
54+
yield put(actions.saveContests(contests));
55+
}
56+
},
4557
});
4658

4759
export default LeaderboardSaga;

src/commons/sagas/RequestsSaga.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { call } from 'redux-saga/effects';
22
import { backendParamsToProgressStatus } from 'src/features/grading/GradingUtils';
3-
import { ContestLeaderboardRow, LeaderboardRow } from 'src/features/leaderboard/LeaderboardTypes';
3+
import { ContestLeaderboardRow, LeaderboardContestDetails, LeaderboardRow } from 'src/features/leaderboard/LeaderboardTypes';
44
import { OptionType } from 'src/pages/academy/teamFormation/subcomponents/TeamFormationForm';
55

66
import {
@@ -490,7 +490,7 @@ export const getAllTotalXp = async (tokens: Tokens): Promise<number | null> => {
490490
export const getContestScoreLeaderboard = async (
491491
assessmentId: number,
492492
tokens: Tokens
493-
): Promise<number | null> => {
493+
): Promise<ContestLeaderboardRow[] | null> => {
494494
const resp = await request(
495495
`${courseId()}/leaderboard/contests/${assessmentId}/get_score_leaderboard`,
496496
'GET',
@@ -525,7 +525,7 @@ export const getContestScoreLeaderboard = async (
525525
export const getContestPopularVoteLeaderboard = async (
526526
assessmentId: number,
527527
tokens: Tokens
528-
): Promise<number | null> => {
528+
): Promise<ContestLeaderboardRow[] | null> => {
529529
const resp = await request(
530530
`${courseId()}/leaderboard/contests/${assessmentId}/get_popular_vote_leaderboard`,
531531
'GET',
@@ -554,6 +554,23 @@ export const getContestPopularVoteLeaderboard = async (
554554
);
555555
};
556556

557+
/**
558+
* GET /courses/{courseId}/all_contests
559+
*/
560+
export const getAllContests = async (tokens: Tokens): Promise<LeaderboardContestDetails[] | null> => {
561+
const resp = await request(`${courseId()}/all_contests`, 'GET', {
562+
...tokens
563+
});
564+
565+
if (!resp || !resp.ok) {
566+
return null; // invalid accessToken _and_ refreshToken
567+
}
568+
569+
const rows = await resp.json();
570+
571+
return rows;
572+
};
573+
557574
/**
558575
* GET /courses/{courseId}/admin/users/{course_reg_id}/assessments
559576
*/
@@ -1257,14 +1274,15 @@ export const calculateContestScore = async (
12571274
};
12581275

12591276
/**
1260-
* GET /courses/{courseId}/admin/assessments/{assessmentId}/scoreLeaderboard
1277+
* GET /courses/{courseId}/admin/assessments/{assessmentId}/{visibleEntries}/scoreLeaderboard
12611278
*/
12621279
export const getScoreLeaderboard = async (
12631280
assessmentId: number,
1281+
visibleEntries: number | undefined,
12641282
tokens: Tokens
12651283
): Promise<ContestEntry[] | null> => {
12661284
const resp = await request(
1267-
`${courseId()}/admin/assessments/${assessmentId}/scoreLeaderboard`,
1285+
`${courseId()}/admin/assessments/${assessmentId}/${visibleEntries}/scoreLeaderboard`,
12681286
'GET',
12691287
{
12701288
...tokens
@@ -1278,14 +1296,15 @@ export const getScoreLeaderboard = async (
12781296
};
12791297

12801298
/**
1281-
* GET /courses/{courseId}/admin/assessments/{assessmentId}/popularVoteLeaderboard
1299+
* GET /courses/{courseId}/admin/assessments/{assessmentId}/{visibleEntries}/popularVoteLeaderboard
12821300
*/
12831301
export const getPopularVoteLeaderboard = async (
12841302
assessmentId: number,
1303+
visibleEntries: number | undefined,
12851304
tokens: Tokens
12861305
): Promise<ContestEntry[] | null> => {
12871306
const resp = await request(
1288-
`${courseId()}/admin/assessments/${assessmentId}/popularVoteLeaderboard`,
1307+
`${courseId()}/admin/assessments/${assessmentId}/${visibleEntries}/popularVoteLeaderboard`,
12891308
'GET',
12901309
{
12911310
...tokens

src/commons/sagas/__tests__/BackendSaga.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ const mockCourseConfiguration1: CourseConfiguration = {
136136
enableSourcecast: true,
137137
enableStories: false,
138138
topLeaderboardDisplay: 100,
139+
topContestLeaderboardDisplay: 10,
139140
sourceChapter: Chapter.SOURCE_1,
140141
sourceVariant: Variant.DEFAULT,
141142
moduleHelpText: 'Help text',
@@ -168,6 +169,7 @@ const mockCourseConfiguration2: CourseConfiguration = {
168169
enableOverallLeaderboard: true,
169170
enableContestLeaderboard: true,
170171
topLeaderboardDisplay: 100,
172+
topContestLeaderboardDisplay: 10,
171173
enableSourcecast: true,
172174
enableStories: false,
173175
sourceChapter: Chapter.SOURCE_4,
@@ -937,6 +939,7 @@ describe('Test UPDATE_COURSE_CONFIG action', () => {
937939
enableOverallLeaderboard: true,
938940
enableContestLeaderboard: true,
939941
topLeaderboardDisplay: 100,
942+
topContestLeaderboardDisplay: 10,
940943
enableSourcecast: false,
941944
enableStories: false,
942945
sourceChapter: Chapter.SOURCE_4,

src/features/leaderboard/LeaderboardActions.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createActions } from 'src/commons/redux/utils';
22

3-
import { ContestLeaderboardRow, LeaderboardRow } from './LeaderboardTypes';
3+
import { ContestLeaderboardRow, LeaderboardContestDetails, LeaderboardRow } from './LeaderboardTypes';
44

55
const LeaderboardActions = createActions('leaderboard', {
66
getAllUsersXp: 0,
@@ -11,7 +11,9 @@ const LeaderboardActions = createActions('leaderboard', {
1111
saveAllContestPopularVotes: (contestPopularVote: ContestLeaderboardRow[]) => contestPopularVote,
1212
getCode: 0,
1313
saveCode: (code: string) => code,
14-
clearCode: 0
14+
clearCode: 0,
15+
getContests: 0,
16+
saveContests: (contests: LeaderboardContestDetails[]) => contests,
1517
});
1618

1719
export default LeaderboardActions;

src/features/leaderboard/LeaderboardReducer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export const LeaderboardReducer: Reducer<LeaderboardState, SourceActionType> = c
2323
})
2424
.addCase(LeaderboardActions.clearCode, (state, action) => {
2525
state.code = '';
26+
})
27+
.addCase(LeaderboardActions.saveContests, (state, action) => {
28+
state.contests = action.payload;
2629
});
2730
}
2831
);

src/features/leaderboard/LeaderboardTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type LeaderboardState = {
2323
contestScore: ContestLeaderboardRow[];
2424
contestPopularVote: ContestLeaderboardRow[];
2525
code: string;
26+
contests: LeaderboardContestDetails[];
2627
};
2728

2829
export type LeaderboardContestDetails = {

0 commit comments

Comments
 (0)