diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 00000000..866f1e13 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.vs/reimplementation-front-end/v17/.wsuo b/.vs/reimplementation-front-end/v17/.wsuo new file mode 100644 index 00000000..26ccafa3 Binary files /dev/null and b/.vs/reimplementation-front-end/v17/.wsuo differ diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 00000000..87f8d0f6 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/package-lock.json b/package-lock.json index 3ef4561e..9b126b17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,13 +18,13 @@ "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", "@types/node": "^16.18.29", - "@types/react": "^18.2.6", - "@types/react-dom": "^18.2.4", + "@types/react": "^18.3.20", + "@types/react-dom": "^18.3.6", "@types/react-redux": "^7.1.25", "@types/react-router-dom": "^5.3.3", "axios": "^1.4.0", "bootstrap": "^5.3.3", - "chart.js": "^3.7.0", + "chart.js": "^4.1.1", "formik": "^2.2.9", "jquery": "^3.7.1", "jwt-decode": "^3.1.2", @@ -38,7 +38,7 @@ "react-redux": "^8.0.5", "react-router-dom": "^6.11.1", "react-scripts": "^5.0.1", - "recharts": "^2.12.3", + "recharts": "^2.0.0", "redux-persist": "^6.0.0", "sass": "^1.62.1", "save": "^2.9.0", @@ -3045,6 +3045,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -4122,9 +4128,10 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, "node_modules/@types/react": { - "version": "18.2.79", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", - "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", + "version": "18.3.20", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz", + "integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -4152,11 +4159,12 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.25", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz", - "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==", - "dependencies": { - "@types/react": "*" + "version": "18.3.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.6.tgz", + "integrity": "sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" } }, "node_modules/@types/react-redux": { @@ -5760,9 +5768,16 @@ } }, "node_modules/chart.js": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz", - "integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg==" + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.8.tgz", + "integrity": "sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } }, "node_modules/check-types": { "version": "11.2.3", @@ -16365,6 +16380,7 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -16603,6 +16619,28 @@ "node": ">= 0.8" } }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", diff --git a/package.json b/package.json index a1ed9d64..adc43e44 100644 --- a/package.json +++ b/package.json @@ -13,14 +13,13 @@ "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", "@types/node": "^16.18.29", - "@types/react": "^18.2.6", - "@types/react-dom": "^18.2.4", + "@types/react": "^18.3.20", + "@types/react-dom": "^18.3.6", "@types/react-redux": "^7.1.25", "@types/react-router-dom": "^5.3.3", "axios": "^1.4.0", "bootstrap": "^5.3.3", "chart.js": "^4.1.1", - "recharts": "^2.0.0", "formik": "^2.2.9", "jquery": "^3.7.1", "jwt-decode": "^3.1.2", @@ -34,6 +33,7 @@ "react-redux": "^8.0.5", "react-router-dom": "^6.11.1", "react-scripts": "^5.0.1", + "recharts": "^2.0.0", "redux-persist": "^6.0.0", "sass": "^1.62.1", "save": "^2.9.0", diff --git a/src/App.tsx b/src/App.tsx index 27736ba3..70b6b152 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -68,7 +68,7 @@ function App() { { path: "assignments/edit/:id/assignreviewer", element: , - loader: loadAssignment, + loader: loadAssignment, }, { path: "assignments/edit/:id/viewsubmissions", diff --git a/src/pages/Assignments/AssignReviewer.tsx b/src/pages/Assignments/AssignReviewer.tsx index 925c0e28..36fdb5bb 100644 --- a/src/pages/Assignments/AssignReviewer.tsx +++ b/src/pages/Assignments/AssignReviewer.tsx @@ -1,96 +1,127 @@ -import React, { useMemo } from 'react'; -import { Button, Container, Row, Col } from 'react-bootstrap'; -// import { useNavigate } from 'react-router-dom'; +import React, { useState, useMemo } from 'react'; +import { Button, Container } from 'react-bootstrap'; import { useLoaderData } from 'react-router-dom'; import Table from "components/Table/Table"; import { createColumnHelper } from "@tanstack/react-table"; -interface IReviewer { - id: number; - name: string; +interface IReviewerAssignment { + topic: string; + contributor: string; + reviewers: string[]; // Allow multiple reviewers } - -const columnHelper = createColumnHelper(); +const columnHelper = createColumnHelper(); const AssignReviewer: React.FC = () => { const assignment: any = useLoaderData(); - // const navigate = useNavigate(); - // Dummy data for reviewers - const reviewers = useMemo(() => [ - { id: 1, name: 'Reviewer 1' }, - { id: 2, name: 'Reviewer 2' }, - { id: 3, name: 'Reviewer 3' }, - // ...other reviewers - ], []); + // Dummy data for table + const [data, setData] = useState([ + { topic: 'Topic A', contributor: 'Alice', reviewers: ['Reviewer 1'] }, + { topic: 'Topic B', contributor: 'Bob', reviewers: ['Reviewer 2', 'Reviewer 3'] }, + { topic: 'Topic C', contributor: 'Charlie', reviewers: [] }, + ]); + + const addReviewer = (topic: string) => { + setData(prevData => + prevData.map(row => + row.topic === topic && row.reviewers.length < 3 + ? { ...row, reviewers: [...row.reviewers, `Reviewer ${row.reviewers.length + 1}`] } + : row + ) + ); + }; - const columns = useMemo(() => [ - columnHelper.display({ - id: 'select', - header: () => 'Select', - cell: () => ( - // Center the checkbox + const deleteReviewer = (topic: string, reviewer: string) => { + setData(prevData => + prevData.map(row => + row.topic === topic + ? { ...row, reviewers: row.reviewers.filter(r => r !== reviewer) } + : row ) - }), - columnHelper.accessor('name', { - header: () => 'Reviewer', + ); + }; + + const unsubmitReviewer = (topic: string, reviewer: string) => { + console.log(`Unsubmitted ${reviewer} for topic ${topic}`); + // Logic for unsubmitting a reviewer can be added here + }; + + const columns = useMemo(() => [ + columnHelper.accessor('topic', { + header: 'Topic Selected', + cell: info => info.getValue() + }), + + columnHelper.accessor('contributor', { + header: 'Contributor', cell: info => info.getValue() }), - columnHelper.display({ - id: 'actions', - header: () => 'Action', - cell: () => ( - - ) - }) - ], []); - const handleAssignReviewers = () => { - console.log('Assigned reviewers'); - // Logic to assign selected reviewers goes here - }; + columnHelper.accessor('reviewers', { + header: 'Reviewed By', + cell: info => { + const { reviewers } = info.row.original; + const topic = info.row.original.topic; - // const handleClose = () => { - // navigate(-1); // Go back to the previous page - // }; + return ( +
+ {/* Display Reviewers */} + {reviewers.map((reviewer, index) => ( +
+ {reviewer} + + +
+ ))} - return ( - -
- This is a placeholder page and is still in progress. -
- - -

Assign Reviewer - {assignment.name}

- -
-
- - - addReviewer(topic)} + > + Add Reviewer + + )} + + ); + } + }), + ], [data]); - }} - /> - - - - - {/* */} -
+
+ - - - +
+ + ); }; - -export default AssignReviewer; \ No newline at end of file + export default AssignReviewer; diff --git a/src/pages/Assignments/Assignment.tsx b/src/pages/Assignments/Assignment.tsx index b178162a..74a6c52b 100644 --- a/src/pages/Assignments/Assignment.tsx +++ b/src/pages/Assignments/Assignment.tsx @@ -1,3 +1,4 @@ +import dummyTopicData from "./Data/DummyTopics.json"; import { Button, Col, Container, Row } from "react-bootstrap"; import { Outlet, useLocation, useNavigate } from "react-router-dom"; import { useCallback, useEffect, useMemo, useState } from "react"; @@ -128,4 +129,4 @@ const Assignments = () => { ); }; -export default Assignments; \ No newline at end of file +export default Assignments; diff --git a/src/pages/Assignments/AssignmentEditor.tsx b/src/pages/Assignments/AssignmentEditor.tsx index bde49592..5a3a29dc 100644 --- a/src/pages/Assignments/AssignmentEditor.tsx +++ b/src/pages/Assignments/AssignmentEditor.tsx @@ -182,7 +182,7 @@ const AssignmentEditor: React.FC = ({ mode }) => { Create Teams -
navigate(`/assignments/edit/${assignmentData.id}/assignreviewer`)}> +
navigate(`/assignments/edit/assignreviewer`)}> Assign Reviewer
@@ -211,4 +211,4 @@ const AssignmentEditor: React.FC = ({ mode }) => { ); }; -export default AssignmentEditor; \ No newline at end of file +export default AssignmentEditor; diff --git a/src/pages/Assignments/AssignmentUtil.ts b/src/pages/Assignments/AssignmentUtil.ts index 0bb183da..c28df696 100644 --- a/src/pages/Assignments/AssignmentUtil.ts +++ b/src/pages/Assignments/AssignmentUtil.ts @@ -12,6 +12,7 @@ export interface IAssignmentFormValues { has_badge:boolean; staggered_deadline:boolean; is_calibrated:boolean; + max_team_size: number; } @@ -26,6 +27,36 @@ export const transformAssignmentRequest = (values: IAssignmentFormValues) => { has_badge:values.has_badge, staggered_deadline:values.staggered_deadline, is_calibrated:values.is_calibrated, + submitter_count: values.submitter_count, + num_reviews: values.num_reviews, + num_review_of_reviews: values.num_review_of_reviews, + num_review_of_reviewers: values.num_review_of_reviewers, + num_reviewers: values.num_reviewers, + max_team_size: values.max_team_size, + days_between_submissions: values.days_between_submissions, + review_assignment_strategy: values.review_assignment_strategy, + max_reviews_per_submission: values.max_reviews_per_submission, + review_topic_threshold: values.review_topic_threshold, + rounds_of_reviews: values.rounds_of_reviews, + num_quiz_questions: values.num_quiz_questions, + late_policy_id: values.late_policy_id, + max_bids: values.max_bids, + reviews_visible_to_all: values.reviews_visible_to_all, + allow_suggestions: values.allow_suggestions, + copy_flag: values.copy_flag, + microtask: values.microtask, + is_coding_assignment: values.is_coding_assignment, + is_intelligent: values.is_intelligent, + calculate_penalty: values.calculate_penalty, + is_penalty_calculated: values.is_penalty_calculated, + availability_flag: values.availability_flag, + use_bookmark: values.use_bookmark, + can_review_same_topic: values.can_review_same_topic, + can_choose_topic_to_review: values.can_choose_topic_to_review, + }; + return assignment; +}; + }; console.log(assignment); diff --git a/src/pages/Assignments/dmdView.tsx b/src/pages/Assignments/dmdView.tsx new file mode 100644 index 00000000..2f381e9a --- /dev/null +++ b/src/pages/Assignments/dmdView.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import { Contributor } from 'utils/interfaces'; + +type Props = { + assignmentId: number; + contributors: Contributor[]; + hasSignupSheet: boolean; +}; + +const ContributorTable: React.FC = ({ contributors, hasSignupSheet, assignmentId }) => { + return ( +
+ + + {hasSignupSheet && } + + + + + + + {contributors.map((contributor, i) => { + const bgColor = i % 2 === 0 ? 'bg-yellow-50' : 'bg-gray-100'; + + return ( + + {hasSignupSheet && ( + + )} + + + + ); + })} + +
Topic selectedContributorReviewed ByMetareviewed By
+ {/* TODO Render topics here */} + {/* TODO precompute or fetch this separately */} + + {contributor.users.map(user => ( +
+ {user.full_name} ({user.name}) +
+ ))} + +
+ + {contributor.reviewMappings.map((map, j) => { + const bg2 = j % 2 === 0 ? 'bg-yellow-100' : 'bg-yellow-200'; + return ( + + + + + ); + })} +
+ {map.reviewer.name} ({map.reviewer.full_name}) +
+ Review Status: {map.response_status} +
+ delete
+ add metareviewer
+ delete all metareviewers +
+
+ + {map.metareview_mappings.map((rmap: any, k: number) => { + const bg3 = k % 2 === 0 ? 'bg-white' : 'bg-gray-300'; + return ( + + + + ); + })} +
+ {rmap.reviewer.name} ({rmap.reviewer.full_name}) +
+ delete +
+
+
+
+ ); +}; + +export default ContributorTable; + diff --git a/src/pages/ViewTeamGrades/Data/DummyTopics.json b/src/pages/ViewTeamGrades/Data/DummyTopics.json new file mode 100644 index 00000000..b40baa8e --- /dev/null +++ b/src/pages/ViewTeamGrades/Data/DummyTopics.json @@ -0,0 +1,53 @@ +[ + { + "topic": "E2450. Refactor assignments_controller.rb", + "contributors": [ + { "name": "Alice anna", "username": "alice123" }, + { "name": "Bob sam", "username": "bob456" } + ], + "reviewers": [ + { "name": "User1", "username": "username1", "status": "Submitted" } + ] + }, + { + "topic": "E2451. Reimplement feedback_response_map.rb", + "contributors": [ + { "name": "Bob sam", "username": "bob123" }, + { "name": "Eve wesley", "username": "eve123" } + ], + "reviewers": [ + { "name": "user2", "username": "username2", "status": "Pending" }, + { "name": "user3", "username": "username3", "status": "Submitted" } + ] + }, + { + "topic": "E2452. Refactor review_mapping_controller.rb", + "contributors": [ + { "name": "Charlie boo", "username": "charlie123" } + ], + "reviewers": [] + }, + { + "topic": "E2458. User management and users table", + "contributors": [ + { "name": "Harley jad", "username": "harley123" }, + { "name": "Javed son", "username": "javed1234" }, + { "name": "Leo mee", "username": "leo123" } + ], + "reviewers": [ + { "name": "user2", "username": "username2", "status": "Pending" }, + { "name": "user3", "username": "username3", "status": "Submitted" } + ] + }, + { + "topic": "E2467. UI for View Submissions", + "contributors": [ + { "name": "Shadow box", "username": "shadow123" }, + { "name": "Bradon kin", "username": "bradon123" } + ], + "reviewers": [ + { "name": "user2", "username": "username2", "status": "Pending" }, + { "name": "user3", "username": "username3", "status": "Submitted" } + ] + } + ] diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index 5aa18db7..5174d49a 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -1,3 +1,4 @@ +import dummyTopicData from "./Data/DummyTopics.json"; import React, { useEffect, useState } from "react"; import ReviewTableRow from "./ReviewTableRow"; import RoundSelector from "./RoundSelector"; @@ -213,6 +214,8 @@ const ReviewTable: React.FC = () => { Late Penalty: {dummyData.late_penalty}

+
+ Back
diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index 213909c9..4469820a 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -86,7 +86,9 @@ export interface IAssignmentRequest { require_quiz:boolean, has_badge:boolean, staggered_deadline:boolean, - is_calibrated:boolean, + is_calibrated: boolean, + max_team_size: number; + } export interface ITAResponse { @@ -164,10 +166,36 @@ export interface IAssignmentResponse { require_quiz:boolean; has_badge:boolean; staggered_deadline:boolean; - is_calibrated:boolean; + is_calibrated: boolean; + max_team_size: number; } +export interface Topic { + topic_identifier: string; + topic_name: string; + is_waitlisted?: boolean; +} +export interface Contributor { + id: number; + name: string; + type: 'AssignmentTeam' | 'AssignmentParticipant '; + users: IUserRequest[]; + reviewMappings: ReviewMapping[]; + +} + +export interface ReviewMapping { + map_id: number; + reviewer: IUserRequest; // todo figure out if this should be UserRequest or response + review_status: 'Assigned' | 'Saved' | 'Submitted'; + metareview_mappings: MetaReviewMapping[]; +} + +export interface MetaReviewMapping { + map_id: number; + reviewer: IUserRequest; // todo figure out if this should be UserRequest or response +} // Assuming that your transformation function for assignment responses might look like this export const transformAssignmentResponse = (assignmentResponse: string): IAssignmentResponse => {