CSC/ECE 517 Fall 2025 - E2568. Finish tabbed view for Assignments, including Topics and Calibration tabs: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
Line 12: Line 12:
* Tab header should be "Submit reviews for calibration"
* Tab header should be "Submit reviews for calibration"
* Table should have three columns titled:
* Table should have three columns titled:
** Participant name: displays the name in the format of "unityid (Full Name)"
** Participant name: displays the name in the format of "user-ID (Name)"
** Action: contains a link to "Begin" that once clicked changes to the links "View" and "Edit"
** Action: contains a link to "Begin" that once clicked changes to the links "View" and "Edit"
** Submitted item(s): provides a view of the submitted calibration materials
** Submitted item(s): provides a view of the submitted calibration materials

Latest revision as of 21:42, 8 December 2025

Introduction

Overview

This project is a continuation of E2558. The Edit Assignment front end will get an additional tab for review calibration based on the backend work of E2564. Additionally, the Topics tab created as part of E2558 will be integrated with the topic table created by E2557. A more comprehensive testing suite for the AssignmentEditor tabbed view will also be developed. The images below are samples provided to the team.

Motivation

Expertiza is an open-source assignment management system with support for teams and peer-reviewing. In the context of Expertiza, calibration refers to sample reviews provided for the purpose of determining if a student is a competent reviewer. If the student's reviews align with the samples, the student is assumed to be competent, assisting in grading and review quality. This new frontend will display these instructor-provided sample reviews in the new Calibration tab where they can be viewed and edited. The topic table is used to create, edit, and delete assignment topics, as well as view which students/groups have signed up for which topic once the assignment is live.

Requirements

Calibration Tab

  • Tab header should be "Submit reviews for calibration"
  • Table should have three columns titled:
    • Participant name: displays the name in the format of "user-ID (Name)"
    • Action: contains a link to "Begin" that once clicked changes to the links "View" and "Edit"
    • Submitted item(s): provides a view of the submitted calibration materials

Sample image

Topics Table Integration

  • Communicate with the respective team to ensure compatibility
  • Work with them to adjust any requirements or details

Sample image

Design

Front-end work

  • We need to add a new Calibration tab to the existing setup
  • These changes will happen in the AssignmentEditor.tsx file along with the rest of the editor tabs.
  • Since there's a table to be added, we will use the previously built table component to avoid having to create a custom design. This also helps ensure the design stays consistent with the rest of the site.
  • We'll need to store certain states on this tab to trigger the visibility of other buttons. These states will be stored in the AssignmentUtils.tsx file.
  • To integrate the table from project E2557, we'll have to make changes to the existing tab layout and add any dependencies the new table has.

Back-end work

  • Need to update the database to support the saving of added calibration parameters

Design Principles used

  1. Don't Repeat Yourself: Shared table rendering logic reused via helper components. API utility reused for all fetch calls.
  2. Single Responsibility Principle: Each tab component handles only its own view and logic.
  3. Open/Closed Principle: Since the tabs are modular, we can add new tabs without modifying existing ones. This makes it much easier to add or change them without messing with the rest of the structure.

Testing Plan

  • For frontend tests, we will focus on getting the system setup from scratch since the Assignment Editor doesn't have one as of yet.
  • This will involve adding tests top check whether appropriate components are visible when they should be, and if the different states stored for each tab stay consistent across the session.
  • We'll also focus on checking if the data seen in the tables on the tabs is correct and aligns with what we're fetching from the backend

Implementation

Front-end

Our front-end implementation can be found in AssignmentEditor.tsx, AssignmentUtil.tsx, and AssignmentEditor.test.tsx within src/pages/Assignments. App.tsx and custom.scss were also updated in src to implement correct routing for assignment creation and add the correct tab styling respectively.

Calibration Tab

<Tab eventKey="calibration" title="Calibration">
	<h3>Submit reviews for calibration</h3>
	<div>
		<div style={{ display: 'ruby', marginTop: '30px' }}>
			<Table
				showColumnFilter={false}
                showGlobalFilter={false}
                showPagination={false}
                data={[
                    ...calibrationSubmissions.map((calibrationSubmission: any) => ({
                        id: calibrationSubmission.id,
                        participant_name: calibrationSubmission.participant_name,
                        review_status: calibrationSubmission.review_status,
                        submitted_content: calibrationSubmission.submitted_content,
                    })),
                ]}
                columns={[
                    {
                        accessorKey: "participant_name", header: "Participant name", enableSorting: false, enableColumnFilter: false
                    },
                    {
                        cell: ({ row }) => {
                            if (row.original.review_status === "not_started") {
                                return <a href={`/assignments/edit/${assignmentData.id}/calibration/${row.original.id}`}>Begin</a>;
                            } else {
                                return <div style={{ display: 'flex', alignItems: 'center', columnGap: '5px' }}>
									<a href={`/assignments/edit/${assignmentData.id}/calibration/${row.original.id}`}>View</a>
									|
									<a href={`/assignments/edit/${assignmentData.id}/calibration/${row.original.id}`}>Edit</a>
                                </div>;
                            }
                        },
                        accessorKey: "action", header: "Action", enableSorting: false, enableColumnFilter: false
                    },
                    {
                        cell: ({ row }) => <>
                            <div>Hyperlinks:</div>
                            {
                                row.original.submitted_content.hyperlinks.map((item: any, index: number) => {
									return <a key={index} href={item}>{item}</a>;
                                })
                            }
                            <div style={{ marginTop: '10px' }}>Files:</div>
                            {
                                row.original.submitted_content.files.map((item: any, index: number) => {
									return <a key={index} href={item}>{item}</a>;
                                })
                            }
                        </>,
                        accessorKey: "submitted_content", header: "Submitted items(s)", enableSorting: false, enableColumnFilter: false
                    },
                ]}
            />
        </div>
    </div>
</Tab>

Back-end

The back-end additions are in db/migrate and are called add_frontend_fields_to_assignments.rb, add_remaining_fields_to_assignments.rb, and add_apply_late_policy_to_assignments.rb. The full file names include date codes that are not included here for clarity.

The fields taken from the completed form to be inserted into the database are

export interface AssignmentData {
  id?: number;
  name: string;
  directory_path: string;
  spec_location: string;
  private: boolean;
  show_template_review: boolean;
  require_quiz: boolean;
  has_badge: boolean;
  staggered_deadline: boolean;
  is_calibrated: boolean;

  // Teams / mentors / topics
  has_teams?: boolean;
  max_team_size?: number;
  show_teammate_review?: boolean;
  is_pair_programming?: boolean;
  has_mentors?: boolean;
  has_topics?: boolean;

  // Review strategy / limits
  review_topic_threshold?: number;
  maximum_number_of_reviews_per_submission?: number;
  review_strategy?: string;
  review_rubric_varies_by_round?: boolean;
  review_rubric_varies_by_topic?: boolean;
  review_rubric_varies_by_role?: boolean;
  has_max_review_limit?: boolean;
  set_allowed_number_of_reviews_per_reviewer?: number;
  set_required_number_of_reviews_per_reviewer?: number;
  is_review_anonymous?: boolean;
  is_review_done_by_teams?: boolean;
  allow_self_reviews?: boolean;
  reviews_visible_to_other_reviewers?: boolean;
  number_of_review_rounds?: number;

  // Dates / penalties
  days_between_submissions?: number;
  late_policy_id?: number;
  is_penalty_calculated?: boolean;
  calculate_penalty?: boolean;
  apply_late_policy?: boolean;

  // Deadline toggles
  use_signup_deadline?: boolean;
  use_drop_topic_deadline?: boolean;
  use_team_formation_deadline?: boolean;

  // Rubric weights / notification limits
  weights?: number[];
  notification_limits?: number[];
  use_date_updater?: boolean[];

  // Per-deadline permissions
  submission_allowed?: boolean[];
  review_allowed?: boolean[];
  teammate_allowed?: boolean[];
  metareview_allowed?: boolean[];
  reminder?: number[];

  // Misc flags from the form
  allow_tag_prompts?: boolean;
  course_id?: number;
  has_quizzes?: boolean;
  calibration_for_training?: boolean;
  available_to_students?: boolean;
  allow_topic_suggestion_from_students?: boolean;
  enable_bidding_for_topics?: boolean;
  enable_bidding_for_reviews?: boolean;
  enable_authors_to_review_other_topics?: boolean;
  allow_reviewer_to_choose_topic_to_review?: boolean;
  allow_participants_to_create_bookmarks?: boolean;
  auto_assign_mentors?: boolean;
  staggered_deadline_assignment?: boolean;

  // These are used only in tables / dynamic fields
  questionnaire?: any;
  date_time?: any[];
}

Testing

Another goal for this project as a continuation was to expand our test suite for the tabbed view from E2558. The test file for AssignmentEditor.tsx is currently in the same src/pages/Assignments directory and is named AssignmentEditor.test.tsx. It uses Jest and React testing libraries and mocks to ensure the AssignmentEditor renders properly and that it displays all of the proper tabs and form fields. The tests also cover tab switching and UI updates when certain checkboxes are selected.

Sample Test Code

Render Framework

const renderComponent = (mode: 'create' | 'update' = 'create') => {
    const store = createMockStore();
    return render(
        <Provider store={store}>
            <BrowserRouter>
                <AssignmentEditor mode={mode} />
            </BrowserRouter>
        </Provider>
    );
};

Specific Render Test Example

it('renders Review strategy tab with select', () => {
        renderComponent();
        const reviewStrategyTab = screen.getByText('Review strategy');
        fireEvent.click(reviewStrategyTab);
        expect(screen.getByTestId('select-review_strategy')).toBeInTheDocument();
    });

Mock Example

jest.mock('components/Form/FormSelect', () => ({
    __esModule: true,
    default: ({ name, options }: any) => (
        <select data-testid={`select-${name}`}>
            {options?.map((opt: any) => (
                <option key={opt.value} value={opt.value}>
                    {opt.label}
                </option>
            ))}
        </select>
    ),
}));

Team Members

  • Keyur Gondhalekar
  • Nishad Tardalkar
  • Evan Shea
  • Mentor: Koushik Gudipelly

Additional Resources

Current Project Repos and Pull Requests

Prior Project (E2558)