diff --git a/src/commons/sagas/RequestsSaga.ts b/src/commons/sagas/RequestsSaga.ts index 4282d05e8a..50e95e8626 100644 --- a/src/commons/sagas/RequestsSaga.ts +++ b/src/commons/sagas/RequestsSaga.ts @@ -1128,6 +1128,48 @@ export const deleteSourcecastEntry = async ( return resp; }; +/** + * GET /courses/{courseId}/admin/assessments/{assessmentId}/scoreLeaderboard + */ +export const getScoreLeaderboard = async ( + assessmentId: number, + tokens: Tokens +): Promise => { + const resp = await request( + `${courseId()}/admin/assessments/${assessmentId}/scoreLeaderboard`, + 'GET', + { + ...tokens + } + ); + if (!resp || !resp.ok) { + return null; // invalid accessToken _and_ refreshToken + } + const scoreLeaderboard = await resp.json(); + return scoreLeaderboard as ContestEntry[]; +}; + +/** + * GET /courses/{courseId}/admin/assessments/{assessmentId}/popularVoteLeaderboard + */ +export const getPopularVoteLeaderboard = async ( + assessmentId: number, + tokens: Tokens +): Promise => { + const resp = await request( + `${courseId()}/admin/assessments/${assessmentId}/popularVoteLeaderboard`, + 'GET', + { + ...tokens + } + ); + if (!resp || !resp.ok) { + return null; // invalid accessToken _and_ refreshToken + } + const popularVoteLeaderboard = await resp.json(); + return popularVoteLeaderboard as ContestEntry[]; +}; + /** * POST /courses/{courseId}/admin/assessments/{assessmentId} */ diff --git a/src/pages/academy/groundControl/configureControls/ExportScoreLeaderboardButton.tsx b/src/pages/academy/groundControl/configureControls/ExportScoreLeaderboardButton.tsx new file mode 100644 index 0000000000..76c00fceda --- /dev/null +++ b/src/pages/academy/groundControl/configureControls/ExportScoreLeaderboardButton.tsx @@ -0,0 +1,40 @@ +import { IconNames } from '@blueprintjs/icons'; +import { createGrid, GridOptions } from 'ag-grid-community'; +import { Tokens } from 'src/commons/application/types/SessionTypes'; +import ControlButton from 'src/commons/ControlButton'; +import { getScoreLeaderboard } from 'src/commons/sagas/RequestsSaga'; +import { useSession } from 'src/commons/utils/Hooks'; + +type Props = { + assessmentId: number; +}; + +const ExportScoreLeaderboardButton: React.FC = ({ assessmentId }) => { + const { accessToken, refreshToken } = useSession(); + const tokens = { accessToken, refreshToken } as Tokens; + + // onClick handler for fetching score leaderboard, putting it into a grid and exporting data + const exportScoreLeaderboardToCsv = async () => { + const scoreLeaderbaord = await getScoreLeaderboard(assessmentId, tokens); + const gridContainer = document.createElement('div'); + const gridOptions: GridOptions = { + rowData: scoreLeaderbaord, + columnDefs: [{ field: 'student_name' }, { field: 'answer' }, { field: 'final_score' }] + }; + const api = createGrid(gridContainer, gridOptions); + api.exportDataAsCsv(); + api.destroy(); + }; + + return ( +
+ +
+ ); +}; + +export default ExportScoreLeaderboardButton; diff --git a/src/pages/academy/groundControl/configureControls/ExportVoteLeaderboardButton.tsx b/src/pages/academy/groundControl/configureControls/ExportVoteLeaderboardButton.tsx new file mode 100644 index 0000000000..b0cc8cf286 --- /dev/null +++ b/src/pages/academy/groundControl/configureControls/ExportVoteLeaderboardButton.tsx @@ -0,0 +1,40 @@ +import { IconNames } from '@blueprintjs/icons'; +import { createGrid, GridOptions } from 'ag-grid-community'; +import { Tokens } from 'src/commons/application/types/SessionTypes'; +import ControlButton from 'src/commons/ControlButton'; +import { getPopularVoteLeaderboard } from 'src/commons/sagas/RequestsSaga'; +import { useSession } from 'src/commons/utils/Hooks'; + +type Props = { + assessmentId: number; +}; + +const ExportVoteLeaderboardButton: React.FC = ({ assessmentId }) => { + const { accessToken, refreshToken } = useSession(); + const tokens = { accessToken, refreshToken } as Tokens; + + // onClick handler for fetching popular vote leaderboard, putting it into a grid and exporting data + const exportPopularVoteLeaderboardToCsv = async () => { + const popularVoteLeaderboard = await getPopularVoteLeaderboard(assessmentId, tokens); + const gridContainer = document.createElement('div'); + const gridOptions: GridOptions = { + rowData: popularVoteLeaderboard, + columnDefs: [{ field: 'student_name' }, { field: 'answer' }, { field: 'final_score' }] + }; + const api = createGrid(gridContainer, gridOptions); + api.exportDataAsCsv(); + api.destroy(); + }; + + return ( +
+ +
+ ); +}; + +export default ExportVoteLeaderboardButton; diff --git a/src/pages/academy/groundControl/subcomponents/GroundControlConfigureCell.tsx b/src/pages/academy/groundControl/subcomponents/GroundControlConfigureCell.tsx index d6ed7542f3..2786b45949 100644 --- a/src/pages/academy/groundControl/subcomponents/GroundControlConfigureCell.tsx +++ b/src/pages/academy/groundControl/subcomponents/GroundControlConfigureCell.tsx @@ -13,6 +13,8 @@ import React, { useCallback, useState } from 'react'; import { AssessmentOverview } from '../../../../commons/assessment/AssessmentTypes'; import ControlButton from '../../../../commons/ControlButton'; +import ExportScoreLeaderboardButton from '../configureControls/ExportScoreLeaderboardButton'; +import ExportVoteLeaderboardButton from '../configureControls/ExportVoteLeaderboardButton'; import AssignEntriesButton from './configureControls/AssignEntriesButton'; type Props = { @@ -112,20 +114,8 @@ const ConfigureCell: React.FC = ({ />
-
- -
-
- -
+ +