Skip to content

Commit

Permalink
feat: Updated rubrics to 1.2.0, which includes groups [PT-188024567]
Browse files Browse the repository at this point in the history
This adds support for the new top level criteria groups in rubrics.
  • Loading branch information
dougmartin committed Aug 23, 2024
1 parent b08ccff commit b699c62
Show file tree
Hide file tree
Showing 23 changed files with 419 additions and 200 deletions.
145 changes: 90 additions & 55 deletions css/portal-dashboard/feedback/rubric-table.less
Original file line number Diff line number Diff line change
Expand Up @@ -83,76 +83,111 @@

.rubricTable {

.rubricTableRow {
code {
font-family: monospace;
}

.rubricTableGroup {
display: flex;
border-top: solid 1.5px @cc-charcoal-light1;

.rubricDescription {
padding: 5px 10px;
font-weight: normal;
flex: auto;
li {
margin-left: 20px;
list-style-type: disc;
}
border-top: solid 1.5px #979797;

.rubricTableGroupLabel {
writing-mode: vertical-rl;
padding: 20px 40px;
border-left: solid 1.5px #979797; // left is really right due to rotation
transform: rotate(180deg);
text-align: center;
font-weight: bold;
}

.ratingsGroup{
.rubricTableRows {
display: flex;
min-height: 45px;
flex-direction: column;
flex: 1;

.rubricScoreBox {
.rubricTableRow {
display: flex;
align-items: center;
justify-content: center;
width: 92px;
flex-grow: 0;
flex-shrink: 0;
border-left: solid 1.5px @cc-charcoal-light1;
border-top: solid 1.5px @cc-charcoal-light1;
flex: 1;
align-items: stretch;

.rubricButton{
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
margin: 5px;
cursor: pointer;

&:hover .outerCircle {
background-color: white;

&:hover .innerCircle {
background-color: @feedback-green-light3B;
}
&:first-child {
border: none;
}

.rubricDescription {
padding: 5px 10px;
font-weight: normal;
flex: auto;

img {
padding-right: 10px;
}
&:active .outerCircle {
background-color: @feedback-green;

&:active .innerCircle {
background-color: white;
}
li {
margin-left: 20px;
list-style-type: disc;
}
}

.ratingsGroup{
display: flex;
min-height: 45px;

.outerCircle {
.rubricScoreBox {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
border-radius: 50%;
border: solid 1.5px @cc-charcoal-light1;
background-color: white;
cursor: pointer;

.innerCircle {
width: 12px;
height: 12px;
background-color: white;
border-radius: 50%;

&.selected {
width: 92px;
flex-grow: 0;
flex-shrink: 0;
border-left: solid 1.5px @cc-charcoal-light1;

.rubricButton{
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
margin: 5px;
cursor: pointer;

&:hover .outerCircle {
background-color: white;

&:hover .innerCircle {
background-color: @feedback-green-light3B;
}
}
&:active .outerCircle {
background-color: @feedback-green;

&:active .innerCircle {
background-color: white;
}
}

.outerCircle {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
border-radius: 50%;
border: solid 1.5px @cc-charcoal-light1;
background-color: white;
cursor: pointer;

.innerCircle {
width: 12px;
height: 12px;
background-color: white;
border-radius: 50%;

&.selected {
background-color: @feedback-green;
}
}
}
}
}
Expand Down
40 changes: 28 additions & 12 deletions css/report/rubric-box-for-student.less
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,46 @@
border-collapse: collapse;
color: #777;

td, th {
padding: 5px;
border: 1px solid #888;
table, th, td {
border: 1px solid #333;
}

td {
width: 50%;
th, td {
padding: 5px;
}

th {
font-weight: bold;
color: #888;
}

.rating-label {
text-transform: uppercase;
}
td {
vertical-align: top;

p {
padding: 5px;
div {
display: flex;
align-items: center;
gap: 5px;

li {
margin-left: 20px;
list-style-type: disc;
}
}

p {
padding: 5px;
}

ul, ol {
padding-left: 2em;
}
}

ul, ol {
padding-left: 2em;
td.groupLabel {
writing-mode: vertical-rl;
transform: rotate(180deg);
text-align: center;
}
}

2 changes: 2 additions & 0 deletions js/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import fakeClassData from "./data/small-class-data.json";
import { parseUrl, validFsId, urlParam, urlHashParam } from "./util/misc";
import { getActivityStudentFeedbackKey } from "./util/activity-feedback-helper";
import { getFirebaseAppName, signInWithToken } from "./db";
import migrate from "./core/rubric-migrations";

const PORTAL_AUTH_PATH = "/auth/oauth_authorize";
let accessToken: string | null = null;
Expand Down Expand Up @@ -414,6 +415,7 @@ export function fetchRubric(rubricUrl: string) {
.then(checkStatus)
.then(response => response.json())
.then(newRubric => {
newRubric = migrate(newRubric);
rubricUrlCache[rubricUrl] = newRubric;
resolve({ url: rubricUrl, rubric: newRubric });
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface IProps {
feedbackSortByMethod: string;
isAnonymous: boolean;
rubric: Rubric;
rubricDocUrl: string;
setFeedbackSortRefreshEnabled: (value: boolean) => void;
students: Map<any, any>;
updateActivityFeedback: (activityId: string, activityIndex: number, platformStudentId: string, feedback: any) => void;
Expand All @@ -33,7 +34,7 @@ interface IProps {

export const ActivityLevelFeedbackStudentRows: React.FC<IProps> = (props) => {
const { activityId, activityIndex, feedbacks, feedbackSortByMethod, isAnonymous, rubric, setFeedbackSortRefreshEnabled,
students, trackEvent, updateActivityFeedback, scoringSettings, activity, isResearcher } = props;
students, trackEvent, updateActivityFeedback, scoringSettings, activity, isResearcher, rubricDocUrl } = props;
const displayedFeedbacks = feedbackSortByMethod !== SORT_BY_FEEDBACK_PROGRESS
? feedbacks
: students.map((student: any) => {
Expand Down Expand Up @@ -75,6 +76,7 @@ export const ActivityLevelFeedbackStudentRows: React.FC<IProps> = (props) => {
activityId={activityId}
activityIndex={activityIndex}
rubric={rubric}
rubricDocUrl={rubricDocUrl}
student={student}
rubricFeedback={rubricFeedback}
setFeedbackSortRefreshEnabled={setFeedbackSortRefreshEnabled}
Expand Down
5 changes: 3 additions & 2 deletions js/components/portal-dashboard/feedback/feedback-legend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface IProps {
activity: Map<any, any>;
scoringSettings: ScoringSettings;
rubric: Rubric;
rubricDocUrl: string;
avgScore: number;
avgScoreMax: number;
feedbacks: any;
Expand All @@ -31,7 +32,7 @@ interface IProps {
}

const FeedbackLegend: React.FC<IProps> = (props) => {
const { feedbackLevel, activity, scoringSettings, avgScore, avgScoreMax, rubric, feedbacks, trackEvent, isResearcher } = props;
const { feedbackLevel, activity, scoringSettings, avgScore, avgScoreMax, rubric, rubricDocUrl, feedbacks, trackEvent, isResearcher } = props;
const { scoreType } = scoringSettings;
const awaitingFeedbackIcon = feedbackLevel === "Activity"
? <AwaitingFeedbackActivityBadgeIcon />
Expand Down Expand Up @@ -73,7 +74,7 @@ const FeedbackLegend: React.FC<IProps> = (props) => {
</div>}
{rubric && <div className={css.feedbackBadgeLegend__rubric_summary}>
Rubric Summary:
<RubricSummaryIcon rubric={rubric} scoringSettings={scoringSettings} feedbacks={feedbacks} activityId={activity.get("id")} trackEvent={trackEvent} />
<RubricSummaryIcon rubric={rubric} rubricDocUrl={rubricDocUrl} scoringSettings={scoringSettings} feedbacks={feedbacks} activityId={activity.get("id")} trackEvent={trackEvent} />
</div>}
</div>
</div>
Expand Down
44 changes: 26 additions & 18 deletions js/components/portal-dashboard/feedback/rubric-summary-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import css from "../../../../css/portal-dashboard/feedback/rubric-summary-icon.l

interface IProps {
rubric: Rubric;
rubricDocUrl: string;
feedbacks: any;
activityId: string;
scoringSettings: ScoringSettings;
Expand All @@ -32,7 +33,7 @@ const maxIconHeight = Math.round(iconWidth / 1.66); // keep rectangular
const defaultIconRowHeight = 18;

export const RubricSummaryIcon: React.FC<IProps> = (props) => {
const { rubric, feedbacks, activityId, scoringSettings, trackEvent } = props;
const { rubric, rubricDocUrl, feedbacks, activityId, scoringSettings, trackEvent } = props;
const [modalOpen, setModalOpen] = useState(false);

const handleToggleModal = () => setModalOpen(prev => {
Expand All @@ -57,9 +58,13 @@ export const RubricSummaryIcon: React.FC<IProps> = (props) => {
.map((f: any) => f.get("rubricFeedback"))
.toJS();

const numCriteria = rubric.criteriaGroups.reduce((acc, cur) => {
return acc + cur.criteria.length;
}, 0);

const numCompletedRubrics = rubricFeedbacks.reduce((acc: number, cur: PartialRubricFeedback) => {
const numNonZeroScores = getNumNonZeroScores(cur);
if (numNonZeroScores >= rubric.criteria.length) {
if (numNonZeroScores >= numCriteria) {
acc++;
}
return acc;
Expand All @@ -72,23 +77,25 @@ export const RubricSummaryIcon: React.FC<IProps> = (props) => {
return acc;
}, {});

rubric.criteria.forEach(criteria => {
const criteriaCount: ICriteriaCount = {
id: criteria.id,
numStudents: 0,
ratings: {...ratingsCounts},
};
criteriaCounts.push(criteriaCount);

rubricFeedbacks.forEach((rubricFeedback: PartialRubricFeedback) => {
const numNonZeroScores = getNumNonZeroScores(rubricFeedback);
if (numNonZeroScores >= rubric.criteria.length) {
const criteriaFeedback = rubricFeedback[criteria.id];
if (criteriaFeedback?.score > 0) {
criteriaCount.numStudents++;
criteriaCount.ratings[criteriaFeedback.id]++;
rubric.criteriaGroups.forEach(criteriaGroup => {
criteriaGroup.criteria.forEach(criteria => {
const criteriaCount: ICriteriaCount = {
id: criteria.id,
numStudents: 0,
ratings: {...ratingsCounts},
};
criteriaCounts.push(criteriaCount);

rubricFeedbacks.forEach((rubricFeedback: PartialRubricFeedback) => {
const numNonZeroScores = getNumNonZeroScores(rubricFeedback);
if (numNonZeroScores >= numCriteria) {
const criteriaFeedback = rubricFeedback[criteria.id];
if (criteriaFeedback?.score > 0) {
criteriaCount.numStudents++;
criteriaCount.ratings[criteriaFeedback.id]++;
}
}
}
});
});
});
}
Expand Down Expand Up @@ -137,6 +144,7 @@ export const RubricSummaryIcon: React.FC<IProps> = (props) => {
{modalOpen && <RubricSummaryModal
onClose={handleToggleModal}
rubric={rubric}
rubricDocUrl={rubricDocUrl}
criteriaCounts={criteriaCounts}
scoringSettings={scoringSettings}
/>}
Expand Down
Loading

0 comments on commit b699c62

Please sign in to comment.