Skip to content

Commit

Permalink
Add Team Assessments (#2548)
Browse files Browse the repository at this point in the history
* Migrate ground control table to tanstack, without filtering and sorting functionalities

* Add filter to ground control table

* Remove defualt filter for ground control table

* Add team size column for ground control table

* Add ID to ground control table

* Update team size edit cell

* Add team size edit column for ground control

* Remove console logs

* Replace row-wise update button with one update button

* Fix bug of team size edit cell not responding for the first click

* Remove unused logs and dependencies

* Fix dependency warning for ground control

* Establish connection with Backend

* Modify payload for postTeams API Call

* Refetch after successfully creating Teams

* Fix page button in team formation

* Add config file

* Modify response payload for fetching students

* Refetch after successfully updating Teams

* Add Upload CSV API Call

* Update assessment workspace

* Remove console logs

* Add team information page to assessment workspace

* Display names in team info page

* Add team flag to assessment dashboard

* Fix assessment overview card

* Modify request to handle 409 Conflict Response

* Update Upload Teams CSV format

* Change minTeamSize to 0

* Add disable Save button in Assessment Workspace

* Add TeamFormationOverview to SessionState

* Revert changes made by Yiting

* Add assessment type indication: Team or Individual

* Add TeamFormationOverview to AssessmentWorkspce

* Add role checks to remove error 403

* Modify GradingQuestion for team submissions

* Remove console logs

* Remove unused code

* Resolve warning ==

* Add lastModifiedAt field for Answer

* Add Save-Safe

* Update Jest Snapshots

* Write tests for FE components

* Write test for SessionActions

* Remove commented code

* Add comments for API calls

* Retrieve create team error message from BE resp

* Add Workspace for TeamFormation

* Update Team Formation Table Filter

* Add Student Name Column Filter

* Fix TeamFormation table global student name filter

* Fix TeamFormation table global student name filter

* Retrieve student username to grading

* Resolve yarn lock

* Split student names in grading editor

* Fix Team Submission for GradingOverview

* Fix Grading Table Header

* Bump Node.js to version 20, update documentation (#2712)

* Create .node-version file

* Add selective WebGL dependency resolution

* Bump node version in CI workflows

* Fix missing dependencies in CI workflow

* Update CD workflow

* Install apt dependencies before building
* Use checkout v3 instead of master
* Replace manual caching strategy with updated setup node action

* Fix typo in CLI option

* Fix insufficient permissions

* Update actions to v4

* Fix resolution warning

* Reorganize documentation

* Create separate CONTRIBUTING.md file for developer-specific items
* Reorganize and reword some sections and sentences

* Update and simplify README instructions

Include references to `.node-version` file and Python dependency, as
well as simplifying some wording.

* Add Python 3.11 disclaimer

* Prettier formatting rules

* Yarn Eslint

* Update snapshot

* Fix yarn run tsc

* Update snapshot

* Update failing snapshots

* Remove package-log.json

Done as the project uses Yarn.

* Restore old environment visualizer snapshots

* Bump follow-redirects from 1.15.2 to 1.15.4 (#2720)

Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](follow-redirects/follow-redirects@v1.15.2...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update field to generate new date

* Remove commented code

* Change student fields to array

* Separate names in Team Formation Table by comma

* Add Team related fields to GradingOverview

* Fix yarn run tsc

* Fix formatting issues

* Remove commented code

* Clean up some code

* Remove console.log statement
* Remove unused stylesheet import
* Remove more commented code

* Update Individual Assignment to have maxTeamSize of 1

* Remove commented code

* Correct API response for GradingOverviews

* Update failing snapshots

* Remove unused code

* Update snapshots post-merge conflict

* Use CSS modules for team formation

* Fix incorrect minimum team size

* Clean up `GroundControlEditTeamSizeCell`

* Update imports
* Update typings
* Remove commented code
* Remove unused type export
* Refactor to use `useCallback`
* Remove unnecessary divs, classes

* Remove unnecessary styles

The styles won't matter for a flex item, thus are removed.

* Remove unnecessary function

* Simplify variable name for readability

* Revert "Remove commented code"

This reverts commit 0cf1f60.

* Fix data flow for editing max team size

* Fix unnecessary API calls

* Reran yarn install post-merge

* Remove unnecessary stub types package

* Fix format post-merge

* Update snapshots post-merge

* Remove TODO comment

The default value of 1 is intentional.

* Make last modified date optional

* Revert "Make last modified date optional"

This reverts commit 6bebb24.

* Update snapshots post-merge

* Migrate new action creators to RTK

* Fix incorrect past merge conflict resolution

* Improve codebase consistency

* Update lockfile

* Update snapshots post-merge

* Format files post-merge

* Fix errors post-merge

* Restore comment

* Fix incorrect condition check

* Update lockfile post merge

* Migrate team actions to RTK

* Fix tests

* Fix compile error post-merge

* Fix lint

---------

Co-authored-by: Lu Yiting <[email protected]>
Co-authored-by: Richard Dominick <[email protected]>
  • Loading branch information
3 people authored Mar 26, 2024
1 parent e804445 commit f4ee0b6
Show file tree
Hide file tree
Showing 56 changed files with 3,606 additions and 351 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"react-copy-to-clipboard": "^5.1.0",
"react-debounce-render": "^8.0.2",
"react-dom": "^18.2.0",
"react-drag-drop-files": "^2.3.10",
"react-draggable": "^4.4.5",
"react-dropzone": "^14.2.3",
"react-hotkeys": "^2.0.0",
Expand All @@ -77,6 +78,7 @@
"react-redux": "^8.1.1",
"react-responsive": "^10.0.0",
"react-router-dom": "^6.14.1",
"react-select": "^5.7.3",
"react-simple-keyboard": "^3.6.27",
"react-sortable-hoc": "^2.0.0",
"react-syntax-highlighter": "^15.5.0",
Expand All @@ -90,6 +92,7 @@
"typesafe-actions": "^5.1.0",
"unified": "^11.0.0",
"uuid": "^9.0.0",
"xlsx": "0.16.4",
"xml2js": "^0.6.0",
"yareco": "^0.1.5"
},
Expand Down
4 changes: 3 additions & 1 deletion src/commons/XMLParser/XMLParserHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ const makeAssessmentOverview = (result: any, maxXpVal: number): AssessmentOvervi
status: AssessmentStatuses.attempting,
story: rawOverview.story,
xp: 0,
gradingStatus: 'none' as GradingStatuses
gradingStatus: 'none' as GradingStatuses,
maxTeamSize: 1
};
};

Expand Down Expand Up @@ -202,6 +203,7 @@ const makeProgramming = (
testcases: publicTestcases.map(testcase => makeTestcase(testcase)),
testcasesPrivate: privateTestcases.map(testcase => makeTestcase(testcase)),
answer: solution ? (solution[0] as string).trim() : '',
lastModifiedAt: new Date().toISOString(),
type: 'programming'
};
if (problem.SNIPPET[0].GRADER) {
Expand Down
17 changes: 17 additions & 0 deletions src/commons/application/ApplicationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,19 @@ export const defaultWorkspaceManager: WorkspaceManagerState = {
currentQuestion: undefined,
hasUnsavedChanges: false
},
teamFormation: {
...createDefaultWorkspace('teamFormation'),
teamFormationTableFilters: {
columnFilters: [],
globalFilter: null
}
},
groundControl: {
...createDefaultWorkspace('groundControl'),
GroundControlTableFilters: {
columnFilters: []
}
},
playground: {
...createDefaultWorkspace('playground'),
usingSubst: false,
Expand Down Expand Up @@ -500,6 +513,8 @@ export const defaultSession: SessionState = {
sessionId: Date.now(),
githubOctokitObject: { octokit: undefined },
gradingOverviews: undefined,
students: undefined,
teamFormationOverviews: undefined,
gradings: new Map<number, GradingQuery>(),
notifications: []
};
Expand Down Expand Up @@ -539,6 +554,8 @@ export const defaultSideContentManager: SideContentManagerState = {
assessment: defaultSideContent,
grading: defaultSideContent,
playground: defaultSideContent,
groundControl: defaultSideContent,
teamFormation: defaultSideContent,
sicp: defaultSideContent,
sourcecast: defaultSideContent,
sourcereel: defaultSideContent,
Expand Down
67 changes: 67 additions & 0 deletions src/commons/application/actions/SessionActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {
paginationToBackendParams,
ungradedToBackendParams
} from 'src/features/grading/GradingUtils';
import { OptionType } from 'src/pages/academy/teamFormation/subcomponents/TeamFormationForm';

import { GradingOverviews, GradingQuery } from '../../../features/grading/GradingTypes';
import { TeamFormationOverview } from '../../../features/teamFormation/TeamFormationTypes';
import {
Assessment,
AssessmentConfiguration,
Expand All @@ -20,8 +22,12 @@ import { Role } from '../ApplicationTypes';
import {
ACKNOWLEDGE_NOTIFICATIONS,
AdminPanelCourseRegistration,
BULK_UPLOAD_TEAM,
CHECK_ANSWER_LAST_MODIFIED_AT,
CourseRegistration,
CREATE_TEAM,
DELETE_ASSESSMENT_CONFIG,
DELETE_TEAM,
DELETE_TIME_OPTIONS,
DELETE_USER_COURSE_REGISTRATION,
FETCH_ADMIN_PANEL_COURSE_REGISTRATIONS,
Expand All @@ -36,6 +42,9 @@ import {
FETCH_GRADING_OVERVIEWS,
FETCH_NOTIFICATION_CONFIGS,
FETCH_NOTIFICATIONS,
FETCH_STUDENTS,
FETCH_TEAM_FORMATION_OVERVIEW,
FETCH_TEAM_FORMATION_OVERVIEWS,
FETCH_TOTAL_XP,
FETCH_TOTAL_XP_ADMIN,
FETCH_USER_AND_COURSE,
Expand Down Expand Up @@ -77,6 +86,10 @@ import {
UPDATE_NOTIFICATION_CONFIG,
UPDATE_NOTIFICATION_PREFERENCES,
UPDATE_NOTIFICATIONS,
UPDATE_STUDENTS,
UPDATE_TEAM,
UPDATE_TEAM_FORMATION_OVERVIEW,
UPDATE_TEAM_FORMATION_OVERVIEWS,
UPDATE_TIME_OPTIONS,
UPDATE_TOTAL_XP,
UPDATE_USER_ROLE,
Expand Down Expand Up @@ -137,6 +150,13 @@ export const fetchGradingOverviews = createAction(
) => ({ payload: { filterToGroup, gradedFilter, pageParams, filterParams } })
);

export const fetchTeamFormationOverviews = createAction(
FETCH_TEAM_FORMATION_OVERVIEWS,
(filterToGroup = true) => ({ payload: filterToGroup })
);

export const fetchStudents = createAction(FETCH_STUDENTS, () => ({ payload: {} }));

export const login = createAction(LOGIN, (providerId: string) => ({ payload: providerId }));

export const logoutGoogle = createAction(LOGOUT_GOOGLE, () => ({ payload: {} }));
Expand Down Expand Up @@ -202,6 +222,13 @@ export const submitAnswer = createAction(
(id: number, answer: string | number | ContestEntry[]) => ({ payload: { id, answer } })
);

export const checkAnswerLastModifiedAt = createAction(
CHECK_ANSWER_LAST_MODIFIED_AT,
(id: number, lastModifiedAt: string, saveAnswer: Function) => ({
payload: { id, lastModifiedAt, saveAnswer }
})
);

export const submitAssessment = createAction(SUBMIT_ASSESSMENT, (id: number) => ({ payload: id }));

export const submitGrading = createAction(
Expand Down Expand Up @@ -246,6 +273,46 @@ export const updateGradingOverviews = createAction(
(overviews: GradingOverviews) => ({ payload: overviews })
);

export const fetchTeamFormationOverview = createAction(
FETCH_TEAM_FORMATION_OVERVIEW,
(assessmentId: number) => ({ payload: { assessmentId } })
);

export const createTeam = createAction(
CREATE_TEAM,
(assessment: AssessmentOverview, teams: OptionType[][]) => ({ payload: { assessment, teams } })
);

export const updateTeam = createAction(
UPDATE_TEAM,
(teamId: number, assessment: AssessmentOverview, teams: OptionType[][]) => ({
payload: { teamId, assessment, teams }
})
);

export const deleteTeam = createAction(DELETE_TEAM, (teamId: number) => ({ payload: { teamId } }));

export const bulkUploadTeam = createAction(
BULK_UPLOAD_TEAM,
(assessment: AssessmentOverview, file: File, students: User[] | undefined) => ({
payload: { assessment, file, students }
})
);

export const updateTeamFormationOverviews = createAction(
UPDATE_TEAM_FORMATION_OVERVIEWS,
(overviews: TeamFormationOverview[]) => ({ payload: overviews })
);

export const updateTeamFormationOverview = createAction(
UPDATE_TEAM_FORMATION_OVERVIEW,
(overview: TeamFormationOverview) => ({ payload: overview })
);

export const updateStudents = createAction(UPDATE_STUDENTS, (students: User[]) => ({
payload: students
}));

/**
* An extra id parameter is included here because of
* no id for Grading.
Expand Down
92 changes: 90 additions & 2 deletions src/commons/application/actions/__tests__/SessionActions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Chapter, Variant } from 'js-slang/dist/types';
import { mockStudents } from 'src/commons/mocks/UserMocks';
import {
paginationToBackendParams,
ungradedToBackendParams
} from 'src/features/grading/GradingUtils';

import { GradingOverviews, GradingQuery } from '../../../../features/grading/GradingTypes';
import { TeamFormationOverview } from '../../../../features/teamFormation/TeamFormationTypes';
import { Assessment, AssessmentOverview } from '../../../assessment/AssessmentTypes';
import { Notification } from '../../../notificationBadge/NotificationBadgeTypes';
import { GameState, Role, Story } from '../../ApplicationTypes';
Expand All @@ -21,6 +23,8 @@ import {
FETCH_GRADING,
FETCH_GRADING_OVERVIEWS,
FETCH_NOTIFICATIONS,
FETCH_STUDENTS,
FETCH_TEAM_FORMATION_OVERVIEWS,
FETCH_USER_AND_COURSE,
LOGIN,
REAUTOGRADE_ANSWER,
Expand All @@ -47,7 +51,11 @@ import {
UPDATE_GRADING_OVERVIEWS,
UPDATE_LATEST_VIEWED_COURSE,
UPDATE_NOTIFICATIONS,
UPDATE_USER_ROLE
UPDATE_STUDENTS,
UPDATE_TEAM_FORMATION_OVERVIEW,
UPDATE_TEAM_FORMATION_OVERVIEWS,
UPDATE_USER_ROLE,
User
} from '../../types/SessionTypes';
import {
acknowledgeNotifications,
Expand All @@ -62,6 +70,8 @@ import {
fetchGrading,
fetchGradingOverviews,
fetchNotifications,
fetchStudents,
fetchTeamFormationOverviews,
fetchUserAndCourse,
login,
reautogradeAnswer,
Expand All @@ -88,6 +98,9 @@ import {
updateGradingOverviews,
updateLatestViewedCourse,
updateNotifications,
updateStudents,
updateTeamFormationOverview,
updateTeamFormationOverviews,
updateUserRole
} from '../SessionActions';

Expand Down Expand Up @@ -183,6 +196,31 @@ test('fetchGradingOverviews generates correct action object', () => {
});
});

test('fetchTeamFormationOverviews generates correct default action object', () => {
const action = fetchTeamFormationOverviews();
expect(action).toEqual({
type: FETCH_TEAM_FORMATION_OVERVIEWS,
payload: true
});
});

test('fetchTeamFormationOverviews generates correct action object', () => {
const filterToGroup = false;
const action = fetchTeamFormationOverviews(filterToGroup);
expect(action).toEqual({
type: FETCH_TEAM_FORMATION_OVERVIEWS,
payload: filterToGroup
});
});

test('fetchStudents generates correct action object', () => {
const action = fetchStudents();
expect(action).toEqual({
type: FETCH_STUDENTS,
payload: {}
});
});

test('fetchNotifications generates correct action object', () => {
const action = fetchNotifications();

Expand Down Expand Up @@ -217,6 +255,7 @@ test('setUser generates correct action object', () => {
const user = {
userId: 123,
name: 'test student',
username: 'test student',
courses: [
{
courseId: 1,
Expand Down Expand Up @@ -501,7 +540,8 @@ test('updateAssessmentOverviews generates correct action object', () => {
status: 'not_attempted',
story: null,
xp: 0,
gradingStatus: 'none'
gradingStatus: 'none',
maxTeamSize: 1
}
];
const action = updateAssessmentOverviews(overviews);
Expand Down Expand Up @@ -546,7 +586,9 @@ test('updateGradingOverviews generates correct action object', () => {
maxXp: 500,
studentId: 100,
studentName: 'test student',
studentNames: [],
studentUsername: 'E0123456',
studentUsernames: [],
submissionId: 1,
submissionStatus: 'attempting',
groupName: 'group',
Expand All @@ -564,6 +606,52 @@ test('updateGradingOverviews generates correct action object', () => {
});
});

test('updateStudents generates correct action object', () => {
const students: User[] = mockStudents;

const action = updateStudents(students);
expect(action).toEqual({
type: UPDATE_STUDENTS,
payload: students
});
});

test('updateTeamFormationOverview generates correct action object', () => {
const overview: TeamFormationOverview = {
teamId: 0,
assessmentId: 1,
assessmentName: 'Mission 1',
assessmentType: 'Missions',
studentIds: [0],
studentNames: ['Mark Henry']
};

const action = updateTeamFormationOverview(overview);
expect(action).toEqual({
type: UPDATE_TEAM_FORMATION_OVERVIEW,
payload: overview
});
});

test('updateTeamFormationOverviews generates correct action object', () => {
const overviews: TeamFormationOverview[] = [
{
teamId: 0,
assessmentId: 0,
assessmentName: 'Mission 2',
assessmentType: 'Missions',
studentIds: [0],
studentNames: ['Mark Henry']
}
];

const action = updateTeamFormationOverviews(overviews);
expect(action).toEqual({
type: UPDATE_TEAM_FORMATION_OVERVIEWS,
payload: overviews
});
});

test('updateGrading generates correct action object', () => {
const submissionId = 3;
const grading: GradingQuery = {
Expand Down
18 changes: 18 additions & 0 deletions src/commons/application/reducers/SessionsReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import {
UPDATE_GRADING,
UPDATE_GRADING_OVERVIEWS,
UPDATE_NOTIFICATIONS,
UPDATE_STUDENTS,
UPDATE_TEAM_FORMATION_OVERVIEW,
UPDATE_TEAM_FORMATION_OVERVIEWS,
UPDATE_TOTAL_XP
} from '../types/SessionTypes';

Expand Down Expand Up @@ -122,6 +125,21 @@ export const SessionsReducer: Reducer<SessionState, SourceActionType> = (
...state,
notifications: action.payload
};
case UPDATE_STUDENTS:
return {
...state,
students: action.payload
};
case UPDATE_TEAM_FORMATION_OVERVIEWS:
return {
...state,
teamFormationOverviews: action.payload
};
case UPDATE_TEAM_FORMATION_OVERVIEW:
return {
...state,
teamFormationOverview: action.payload
};
case REMOTE_EXEC_UPDATE_DEVICES:
return {
...state,
Expand Down
Loading

0 comments on commit f4ee0b6

Please sign in to comment.