Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Update assessment page #21

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f2d907b
modified navbar to white with yellow highlight
mfsilva22 Nov 12, 2021
bee7379
added banner component
mfsilva22 Nov 12, 2021
0b48411
added button to page component
mfsilva22 Nov 12, 2021
6e602f8
updated homepageHeading component
mfsilva22 Nov 12, 2021
84a6902
added demoCourse component
mfsilva22 Nov 12, 2021
6db22ba
added banner pricing page
mfsilva22 Nov 12, 2021
7cd147a
edits to contact page
mfsilva22 Nov 12, 2021
501a423
update formatting contact page
mfsilva22 Nov 13, 2021
6cc5380
fixed prettier check
mfsilva22 Nov 13, 2021
612b743
fixed typeScript error
mfsilva22 Nov 13, 2021
a33639e
fixed typeScript error banner
mfsilva22 Nov 13, 2021
fccca14
fixed typescript demoCourse component
mfsilva22 Nov 13, 2021
cc3425b
ran prettier
mfsilva22 Nov 13, 2021
222955f
update to gallery page
mfsilva22 Nov 13, 2021
356415f
added blank assessment page
mfsilva22 Nov 13, 2021
5ab1fd6
prettier fix
mfsilva22 Nov 13, 2021
05636d1
updated gallery title back to original
mfsilva22 Nov 13, 2021
4e5666b
re-added assessment page content
mfsilva22 Nov 13, 2021
25ab67f
prettier fix
mfsilva22 Nov 13, 2021
12fa673
added alt image
mfsilva22 Nov 13, 2021
5cb2a48
more prettier fix
mfsilva22 Nov 13, 2021
c0f2539
looks like prettier on Atom does not work...
mfsilva22 Nov 13, 2021
4c5e70c
removed Row Column component
mfsilva22 Nov 13, 2021
40666a5
removed unused assessment components from gallery page
mfsilva22 Nov 13, 2021
771f44d
moved assessment docs to src/pages folder and updated assessment page
mfsilva22 Nov 13, 2021
6b27911
prettier fix to docs
mfsilva22 Nov 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/components/AssessmentCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import Link from "next/link";
import Image from "../components/Image";

export interface AssessmentCardProps {
assessmentHref: string;
image: File[];
title: string;
body: string;
}

export const AssessmentCard: React.FC<AssessmentCardProps> = ({
assessmentHref,
image,
title,
body,
}) => (
<div className="container-md border my-4 b-white">
<div className="row">
<div className="col-md-4 order-1 py-3">
<Link href={assessmentHref}>
<a style={{ position: "relative" }}>
<Image src={image} alt="assessment page view" />
</a>
</Link>
</div>
<div className="col-md-8 order-2 py-3 px-3">
<h3> {title} </h3>
<p> {body} </p>
</div>
</div>
</div>
);
6 changes: 6 additions & 0 deletions src/components/Banner.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@import "~bootstrap/scss/_functions.scss";
@import "~bootstrap/scss/_variables.scss";

.container {
background-color: $blue-700;
}
30 changes: 30 additions & 0 deletions src/components/Banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";
import classnames from "classnames";

import styles from "./Banner.module.scss";

const Row: React.FC = ({ children }) => (
<div className="row justify-content-centerrr">{children}</div>
);

const Column: React.FC = ({ children }) => (
<div className="col">{children}</div>
);

export interface PageBannerProps {
title: string;
text: string;
}

export const PageBanner: React.FC<PageBannerProps> = ({ title, text }) => (
<div className={classnames("container-fluid py-4", styles.container)}>
<div className="container-md">
<Row>
<Column>
<h1 className="text-white display-3">{title}</h1>
<p className="text-white mt-4 fs-3">{text}</p>
</Column>
</Row>
</div>
</div>
);
17 changes: 17 additions & 0 deletions src/components/ButtonToPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import Link from "next/link";

export interface ButtonToPageProps {
text: string;
page: string;
}

export const ButtonToPage: React.FC<ButtonToPageProps> = ({ text, page }) => (
<div className="row justify-content-center my-2">
<div className="col-md-12 text-center py-3">
<Link href={page}>
<a className="btn btn-warning btn-md">{text}</a>
</Link>
</div>
</div>
);
43 changes: 43 additions & 0 deletions src/components/DemoCourse.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import classnames from "classnames";
import Link from "next/link";

import styles from "./Banner.module.scss";

const Row: React.FC = ({ children }) => (
<div className="row justify-content-centerrr">{children}</div>
);

const Column: React.FC = ({ children }) => (
<div className="col">{children}</div>
);

export interface DemoCourseActionProps {
title: string;
text: string;
button: string;
}

export const DemoCourseAction: React.FC<DemoCourseActionProps> = ({
title,
text,
button,
}) => (
<div className={classnames("container-fluid py-4", styles.container)}>
<div className="container-md">
<Row>
<Column>
<h3 className="text-white display-6">{title}</h3>
<p className="text-white mt-3 fs-6">{text}</p>
</Column>
</Row>
<div className="row justify-content-center my-2">
<div className="col-md-12 text-center">
<Link href="https://www.prairielearn.org/pl/course_instance/128605">
<a className="btn btn-warning btn-lg">{button}</a>
</Link>
</div>
</div>
</div>
</div>
);
2 changes: 1 addition & 1 deletion src/components/HomepageHeading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import classnames from "classnames";
import styles from "./HomepageHeading.module.scss";

export const HomepageHeading: React.FC = ({ children }) => (
<h2 className={classnames(styles.heading, "h2")}>{children}</h2>
<h2 className={classnames(styles.heading, "pb-3 h2")}>{children}</h2>
);
16 changes: 16 additions & 0 deletions src/components/NavLink.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@import "~bootstrap/scss/_functions.scss";
@import "~bootstrap/scss/_variables.scss";

.nav-link {
color: rgba(255, 255, 255, 1);
padding: 0.5rem 1rem;
text-decoration: none;
}

.nav-link:hover {
color: $yellow;
}

.nav-link.active {
color: $yellow;
}
6 changes: 5 additions & 1 deletion src/components/NavLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import Link from "next/link";
import { useRouter } from "next/router";
import classnames from "classnames";

import styles from "./NavLink.module.scss";

interface NavLinkProps {
href: string;
}
Expand All @@ -14,7 +16,9 @@ const NavLink: React.FC<NavLinkProps> = ({ href, children }) => {
return (
<Link href={href}>
<a
className={classnames("nav-link", { "active fw-bold": active })}
className={classnames(styles["nav-link"], styles["nav-item"], {
"active fw-bold ": active,
})}
aria-current={current ? "page" : undefined}
>
{children}
Expand Down
Binary file added src/lib/images/assessment.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/lib/images/question.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions src/lib/markdown-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from "react";

import Head from "next/head";
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";

import mdxComponents from "../lib/mdxComponents";

export interface MarkdownPageProps {
source: MDXRemoteSerializeResult;
title: string;
summary?: string;
}

export const MarkdownPage: React.FC<MarkdownPageProps> = ({
source,
title,
summary,
}) => (
<React.Fragment>
<Head>
<title>{title} | PrairieLearn</title>
</Head>
<div className="container">
<div className="my-5">
<h1 className="display-3">{title}</h1>
{summary && <p className="lead">{summary}</p>}
</div>
<MDXRemote {...source} components={mdxComponents} />
</div>
</React.Fragment>
);
42 changes: 42 additions & 0 deletions src/lib/markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import fs from "fs-extra";
import matter from "gray-matter";
import { MDXRemoteSerializeResult } from "next-mdx-remote";
import { serialize } from "next-mdx-remote/serialize";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";

import loadCodePlugin from "../remarkPlugins/loadCode";
import extractImages from "../remarkPlugins/extractImages";
import { MarkdownPageProps } from "./markdown-page";

export async function serializeMarkdownDocument(
doc: string,
filepath?: string
): Promise<MDXRemoteSerializeResult> {
return serialize(doc, {
mdxOptions: {
remarkPlugins: [loadCodePlugin, extractImages, remarkMath],
rehypePlugins: [rehypeKatex],
filepath,
},
});
}

export async function getPropsForMarkdownFile(
filePath: string
): Promise<MarkdownPageProps> {
const rawContents = await fs.readFile(filePath, "utf8");

const {
content,
data: { title = "NO TITLE", summary = null },
} = matter(rawContents);

const source = await serializeMarkdownDocument(content, filePath);

return {
source,
title,
summary,
};
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions src/pages/assessments/examInstantFeedback/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
title: Exam
summary: Summative assessments that are auto-graded with instant feedback and retry opportunities
prairielearn_url: https://www.prairielearn.org/pl/course_instance/128605/assessment/2310709
---

## Auto-graded randomized exams

Studies have shown that learning and retention of knowledge is enhanced through retrieval practice that incorporates feedback and increased use of formative assessments.
Here we describe how we use PrairieLearn to create quizzes where students get immediate feedback, shortening the feedback cycle between student learning and assessment performance. This shorter cycle enables the use of frequent and second-chance testing, especially in large courses, which has been shown to lead to significant improvements in learning outcomes and better final exam performance.

We will use the assessment [E1: Auto-graded randomized exams](https://www.prairielearn.org/pl/course_instance/128605/assessment/2310709) to highlight some of the PrairieLearn features to deliver auto-graded and randomized exams.

### Instant feedback with retry attempts

Using the default `Exam` configuration in PrairieLearn, students will receive a fixed question variant for each question generator. This feature matches a traditional paper-and-pencil experience, where the student receives one exam with fixed parameters.

By default, PrairieLearn will auto-grade each question in real-time, and provide students with the feedback about correctness. Depending on how instructors define the question points, students can try to fix incorrect answers for the same parameters, and submit other attempts for reduced credit, mimicking the concept of partial credit.

![](student-retry.png)

This short feedback cycle allows students to reach out to instructors right after the test, enabling them to promptly review and clarify any missed contepts, and consequently make adjustments for upcoming assessments.

**Question 1** asks students to compute a variable $c$ given two parameters $a$ and $b$. The formula to compute $c$ is randomized (selected from a set of 4 different formulas) and the parameters $a$ and $b$ are randomized as well. Students have two attempts to complete this question: the first attempt for full credit and the second attempt for partial credit (1/3 points).

**Question 2** asks students to enter the matrix corresponding to a displayed graph, which is generated in real-time based on randomized parameters. Students have two attempts to complete the question. They can also receive partial credit for each attempt, since each entry of the matrix is graded separately.

**Question 3** is highly randomized, in essence mixing 4 different questions into one, since the circuit diagram changes (parallel and series), and the question prompt changes (compute current or resistance).
Since the solution involves multiple computation steps, students get 5 attempts to complete the question for reduced credit.

### Creating exams from question pools

Exams that are delivered asynchronously or in online unproctored environments create an opportunity for _collaborative cheating_, where a student can gain advantage by receiving information about the exam from another student. Generating random exams from pools of problems has been shown to mitigate collaborative cheating. In PrairieLearn, question generators can be selected from what we call **alternative groups or pools**. For example, an alternative group with 4 question generators can select 2 of them at random to create a version of the exam. In the figure below, an exam with 4 questions is created from a set of 8 question generators.

![](assessment-generator.png)

In addition, question generators will create different question variants based on randomized parameters. These question variants will finally build a student exam, where questions appear in random order. Our studies indicate that pools of 3-4 question generators are effective to mitigate cheating.

### Using information from previous exams to generate randomized exams with reduced difficulty variance

A concern with randomized exams is how one can ensure students receive problems of roughly similar difficulty. Problems can be binned into pools by topic coverage and difficulty, but it can be challenging to generate problems of identical difficulty. When creating question generators for the first time, a instructor can use previous experiences to decide which ones should be combined in an alternative group. PrairieLearn will collect data from these questions, which later can be used by instructors to improve fairness of these randomized exams.

![](question-generator.png)

**Question 4** is randomly selected out of a pool of 3 question generators, each one of them asking students to compute a different matrix and/or vector operation, including matrix multiplication and outer product. Each question generator also utilizes randomized parameters. One of the advantages of keeping similar question variants within separate question generators is the easy access to statistics, providing information regarding question and exam fairness. The disadvantage is the cumbersome bookkeeping of question generators, since one may have to coordinate changes to many files when updates are needed.
32 changes: 32 additions & 0 deletions src/pages/assessments/examInstantFeedback/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import classnames from "classnames";
import Link from "next/link";
import Head from "next/head";
import { GetStaticProps } from "next";
import path from "path";

import { getPropsForMarkdownFile } from "../../../lib/markdown";
import { MarkdownPage, MarkdownPageProps } from "../../../lib/markdown-page";

import { PageBanner } from "../../../components/Banner";
import Stack from "../../../components/Stack";
import Image from "../../../components/Image";

import styles from "./index.module.scss";

export default MarkdownPage;

export const getStaticProps: GetStaticProps<MarkdownPageProps> = async () => {
return {
props: await getPropsForMarkdownFile(
path.resolve(
process.cwd(),
"src",
"pages",
"assessments",
"examInstantFeedback",
"docs.md"
)
),
};
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions src/pages/assessments/groupWork/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Group work
summary: Collaborative learning activities
prairielearn_url: https://www.prairielearn.org/pl/course_instance/128605/assessment/2310480
---

## Group Activities

Research shows that collaborative learning can increase student persistence, improve learning outcomes, and foster better classroom cultures. Using PrairieLearn, instructors can provide group activities where students work collaborativelly in the same assessment, which is shared among all the group members.

### Group formation

PrairieLearn provides the option for instructors to pre-arrange teams, or for students to create their own teams. For pre-assigned groups, instructors can select one of the following options:

- upload a CSV file with the group information
- let PrairieLearn assign students to groups at random, given a mininum and maximum group sizes

Instructors can also let students self-assign to groups. This can be especially helpful when giving group activities during lecture, where groups can be created "on-the-fly" depending on the proximity of students. Instructors can also provide the minium and maximum group sizes under this configuration.

For self-assignment, a student will create a group providing a group name. This student will receive a "join code" that can be used by others that want to join the group. Once the group reaches the minimum size, students are able to start the assessment. Every member of the group will have access to the same question variants, and consequently will also share the same grade.

### Facilitating collaboration among teams

The simple creation of students' teams will rarely guarantee that students will work collaboratively. However, successful and productive collaborations can be greatly improved by careful design of the task, assignment of team roles and the use of available technologies to both promote collaborations among students and support the instructors implementing these activities.

Assessments that are based on higher level skills such as _Analyze_, _Evaluate_ and _Create_ from the [Bloom's Taxonomy](https://en.wikipedia.org/wiki/Bloom's_taxonomy) produce more opportunities for students' interactions, where they can learn from each other. Low level skills which require students to remember simple concepts, or apply simple calculations will emphasize the existence of domineering leaders and free loaders. When designing group tasks, we focus on questions that produce discussions and decision-making.

Another strategy to enhance collaborative learning is to provide activities that can be self-managed by the team, such that instructors act only as facilitators instead of source of information. In the course demo, we provide an example that uses JupyterLab notebooks for the [group assessment](https://www.prairielearn.org/pl/course_instance/128605/assessment/2310480). These notebooks can include text, images, and equations for content presentation, and also ask students to perform computations (in this example, using a Python 3 Kernel).

We can use PrairieLearn external grader to check content for correctness. This will help students self-manage their progress. Instructors can define `#grade` cells inside the JupyterLab notebook, which will be auto-graded for instant feedback (see image below).

![](group-page1.png)

Students in the same group will share the same JupyterLab, and the same submission history and scores. Currently the JupyterLab syncs upon saving (real-time synchronization is a work-in-progress).

A lack of clarity and experience in assuming team roles can lead students to default into domineering team leaders or passive free-loaders. Evidence-based practices such as Process Oriented Guided Inquiry Learning ([POGIL](https://pogil.org)) have shown that providing students with structured roles can help them participate more equitably during collaborative learning. We are currently implementing POGIL roles in PrairieLearn.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading