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

Refactor Live Feedback Settings for Assessment Edit and Submission Form #7553

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true
class Course::Assessment::LiveFeedbackSettings::SettingsController < \
Course::Assessment::Controller
def index
@programming_questions = @assessment.programming_questions.includes(:language)
end

def edit
enabled = live_feedback_params[:enabled]
@programming_qns = @assessment.programming_questions

raise ActiveRecord::Rollback unless @programming_qns.update_all(live_feedback_enabled: enabled) &&
@programming_qns.each(&:create_codaveri_problem)
end

private

def live_feedback_params
params.required(:live_feedback_settings).permit(:enabled)
end
end
1 change: 1 addition & 0 deletions app/models/course/assessment/answer/programming.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def generate_live_feedback

should_retrieve_feedback = submission.attempting? &&
current_answer? &&
current_course.component_enabled?(Course::CodaveriComponent) &&
question.live_feedback_enabled
return unless should_retrieve_feedback

Expand Down
1 change: 1 addition & 0 deletions app/views/course/assessment/assessments/edit.json.jbuilder
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ json.mode_switching @assessment.allow_mode_switching?
json.gamified current_course.gamified?
json.isQuestionsValidForKoditsu is_all_questions_programming_type && @programming_qns_invalid_for_koditsu.empty?
json.isKoditsuExamEnabled current_course.component_enabled?(Course::KoditsuPlatformComponent)
json.isCourseCodaveriEnabled current_course.component_enabled?(Course::CodaveriComponent)
cysjonathan marked this conversation as resolved.
Show resolved Hide resolved
json.show_personalized_timeline_features current_course.show_personalized_timeline_features?
json.randomization_allowed current_course.allow_randomization

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true
json.assessments [@assessment] do |assessment|
json.id assessment.id
json.tabId assessment.tab_id
json.categoryId assessment.tab.category_id
json.title assessment.title
json.url course_assessment_path(current_course, assessment)

if current_course.component_enabled?(Course::CodaveriComponent)
json.programmingQuestions @programming_questions do |programming_qn|
next unless CodaveriAsyncApiService.language_valid_for_codaveri?(programming_qn.language)

if programming_qn.title.blank?
question_assessment = assessment.question_assessments.select do |qa|
qa.question_id == programming_qn.question.id
end.first
question_title = question_assessment&.default_title
else
question_title = programming_qn.title
end

json.id programming_qn.id
json.editUrl url_for([:edit, current_course, assessment, programming_qn])
json.assessmentId assessment.id
json.title question_title
json.isCodaveri programming_qn.is_codaveri
json.liveFeedbackEnabled programming_qn.live_feedback_enabled
end
else
json.programmingQuestions []
cysjonathan marked this conversation as resolved.
Show resolved Hide resolved
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true
json.assessments [@assessment] do |assessment|
json.id assessment.id
json.tabId assessment.tab_id
json.categoryId assessment.tab.category_id
json.title assessment.title
json.url course_assessment_path(current_course, assessment)

if current_course.component_enabled?(Course::CodaveriComponent)
json.programmingQuestions @programming_questions do |programming_qn|
next unless CodaveriAsyncApiService.language_valid_for_codaveri?(programming_qn.language)

if programming_qn.title.blank?
question_assessment = assessment.question_assessments.select do |qa|
qa.question_id == programming_qn.question.id
end.first
question_title = question_assessment&.default_title
else
question_title = programming_qn.title
end

json.id programming_qn.id
json.editUrl url_for([:edit, current_course, assessment, programming_qn])
json.assessmentId assessment.id
json.title question_title
json.isCodaveri programming_qn.is_codaveri
json.liveFeedbackEnabled programming_qn.live_feedback_enabled
end
else
json.programmingQuestions []
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ json.assessment do
json.url url_to_material(@assessment.course, @assessment.folder, material)
json.name format_inline_text(material.name)
end
json.isCodaveriEnabled current_course.component_enabled?(Course::CodaveriComponent)
json.isCourseCodaveriEnabled current_course.component_enabled?(Course::CodaveriComponent)
end

current_answer_ids = @submission.current_answers.pluck(:id)
Expand Down
13 changes: 13 additions & 0 deletions client/app/api/course/Assessment/Assessments.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ export default class AssessmentsAPI extends BaseCourseAPI {
return this.client.get(`${this.#urlPrefix}/${assessmentId}/edit`);
}

liveFeedbackSettings(assessmentId) {
return this.client.get(
`${this.#urlPrefix}/${assessmentId}/live_feedback_settings`,
);
}

updateLiveFeedbackSettings(assessmentId, params) {
return this.client.patch(
`${this.#urlPrefix}/${assessmentId}/live_feedback_settings`,
params,
);
}

fetchMonitoringData() {
return this.client.get(
`${this.#urlPrefix}/${this.assessmentId}/monitoring`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ const CodaveriToggleButtons: FC<CodaveriToggleButtonsProps> = (props) => {
for={title}
type={type}
/>
<LiveFeedbackToggleButton assessmentIds={assessmentIds} for={title} />
<LiveFeedbackToggleButton
assessmentIds={assessmentIds}
for={title}
isCourseCodaveriEnabled
/>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { FC, useState } from 'react';
import { Switch } from '@mui/material';

import { updateProgrammingQuestionLiveFeedbackEnabledForAssessments } from 'course/admin/reducers/codaveriSettings';
import { updateLiveFeedbackForAllQuestionsInAssessment } from 'course/assessment/operations/assessments';
import Prompt from 'lib/components/core/dialogs/Prompt';
import { useAppDispatch, useAppSelector } from 'lib/hooks/store';
import toast from 'lib/hooks/toast';
Expand All @@ -15,11 +16,17 @@ import CodaveriSettingsChip from '../CodaveriSettingsChip';
interface LiveFeedbackToggleButtonProps {
assessmentIds: number[];
for: string;
hideChipIndicator?: boolean;
isSpecificAssessment?: boolean;
isCourseCodaveriEnabled?: boolean;
}

const LiveFeedbackToggleButton: FC<LiveFeedbackToggleButtonProps> = (props) => {
const { assessmentIds, for: title, hideChipIndicator } = props;
const {
assessmentIds,
for: title,
isSpecificAssessment,
isCourseCodaveriEnabled,
} = props;
const { t } = useTranslation();

const dispatch = useAppDispatch();
Expand All @@ -40,9 +47,22 @@ const LiveFeedbackToggleButton: FC<LiveFeedbackToggleButtonProps> = (props) => {

const hasNoProgrammingQuestions = programmingQuestions.length === 0;

const updateLiveFeedbackEnabled = (
liveFeedbackEnabled: boolean,
): Promise<void> =>
isSpecificAssessment
? updateLiveFeedbackForAllQuestionsInAssessment(
assessmentIds[0],
liveFeedbackEnabled,
)
: updateLiveFeedbackEnabledForAllQuestions(
assessmentIds,
liveFeedbackEnabled,
);

const handleLiveFeedbackUpdate = (liveFeedbackEnabled: boolean): void => {
setIsLiveFeedbackUpdating(true);
updateLiveFeedbackEnabledForAllQuestions(assessmentIds, liveFeedbackEnabled)
updateLiveFeedbackEnabled(liveFeedbackEnabled)
.then(() => {
dispatch(
updateProgrammingQuestionLiveFeedbackEnabledForAssessments({
Expand Down Expand Up @@ -72,19 +92,23 @@ const LiveFeedbackToggleButton: FC<LiveFeedbackToggleButtonProps> = (props) => {
<div>
<Switch
checked={
hasNoProgrammingQuestions
hasNoProgrammingQuestions || !isCourseCodaveriEnabled
? false
: qnsWithLiveFeedbackEnabled.length ===
programmingQuestions.length
}
color="primary"
disabled={hasNoProgrammingQuestions || isLiveFeedbackUpdating}
disabled={
hasNoProgrammingQuestions ||
!isCourseCodaveriEnabled ||
isLiveFeedbackUpdating
}
onChange={(_, isChecked): void => {
setLiveFeedbackChecked(isChecked);
setLiveFeedbackSettingsConfirmation(true);
}}
/>
{!hideChipIndicator && (
{!isSpecificAssessment && (
<CodaveriSettingsChip
assessmentIds={assessmentIds}
for="live_feedback"
Expand Down
20 changes: 13 additions & 7 deletions client/app/bundles/course/admin/reducers/codaveriSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,26 @@ export const codaveriSettingsSlice = createSlice({
saveAllAssessmentsQuestions: (
state,
action: PayloadAction<{
categories: AssessmentCategoryData[];
tabs: AssessmentTabData[];
categories?: AssessmentCategoryData[];
tabs?: AssessmentTabData[];
assessments: AssessmentProgrammingQuestionsData[];
}>,
) => {
const { categories, tabs, assessments } = action.payload;
const questions = assessments.flatMap(
(assessment) => assessment.programmingQuestions,
);
assessmentCategoriesAdapter.setAll(
state.assessmentCategories,
categories,
);
assessmentTabsAdapter.setAll(state.assessmentTabs, tabs);
if (categories) {
assessmentCategoriesAdapter.setAll(
state.assessmentCategories,
categories,
);
}

if (tabs) {
assessmentTabsAdapter.setAll(state.assessmentTabs, tabs);
}

assessmentsAdapter.setAll(state.assessments, assessments);
programmingQuestionsAdapter.setAll(state.programmingQuestions, questions);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import {
import {
Grid,
InputAdornment,
// List,
List,
RadioGroup,
Typography,
} from '@mui/material';

// import AssessmentProgrammingQnList from 'course/admin/pages/CodaveriSettings/components/AssessmentProgrammingQnList';
// import LiveFeedbackToggleButton from 'course/admin/pages/CodaveriSettings/components/buttons/LiveFeedbackToggleButton';
// import { getProgrammingQuestionsForAssessments } from 'course/admin/pages/CodaveriSettings/selectors';
import AssessmentProgrammingQnList from 'course/admin/pages/CodaveriSettings/components/AssessmentProgrammingQnList';
import LiveFeedbackToggleButton from 'course/admin/pages/CodaveriSettings/components/buttons/LiveFeedbackToggleButton';
import { getProgrammingQuestionsForAssessments } from 'course/admin/pages/CodaveriSettings/selectors';
import IconRadio from 'lib/components/core/buttons/IconRadio';
import ErrorText from 'lib/components/core/ErrorText';
// import ExperimentalChip from 'lib/components/core/ExperimentalChip';
import ExperimentalChip from 'lib/components/core/ExperimentalChip';
import InfoLabel from 'lib/components/core/InfoLabel';
import Section from 'lib/components/core/layouts/Section';
import ConditionsManager from 'lib/components/extensions/conditions/ConditionsManager';
Expand All @@ -29,7 +29,7 @@ import FormDateTimePickerField from 'lib/components/form/fields/DateTimePickerFi
import FormRichTextField from 'lib/components/form/fields/RichTextField';
import FormSelectField from 'lib/components/form/fields/SelectField';
import FormTextField from 'lib/components/form/fields/TextField';
import { useAppDispatch } from 'lib/hooks/store';
import { useAppDispatch, useAppSelector } from 'lib/hooks/store';
import useTranslation from 'lib/hooks/useTranslation';

import FileManager from '../FileManager';
Expand All @@ -52,6 +52,7 @@ const AssessmentForm = (props: AssessmentFormProps): JSX.Element => {
initialValues,
isKoditsuExamEnabled,
isQuestionsValidForKoditsu,
isCourseCodaveriEnabled,
modeSwitching,
onSubmit,
pulsegridUrl,
Expand Down Expand Up @@ -93,20 +94,14 @@ const AssessmentForm = (props: AssessmentFormProps): JSX.Element => {
: t(translations.questionsIncompatibleWithKoditsu);
};

// const assessmentId = initialValues.id;
// const title = initialValues.title;
const assessmentId = initialValues.id;
const title = initialValues.title;

// const programmingQuestions = useAppSelector((state) =>
// getProgrammingQuestionsForAssessments(state, [assessmentId]),
// );

// const qnsWithLiveFeedbackEnabled = programmingQuestions.filter(
// (question) => question.liveFeedbackEnabled,
// );
const programmingQuestions = useAppSelector((state) =>
getProgrammingQuestionsForAssessments(state, [assessmentId]),
);

// const hasNoProgrammingQuestions = programmingQuestions.length === 0;
// const isSomeLiveFeedbackEnabled =
// qnsWithLiveFeedbackEnabled.length < programmingQuestions.length;
const hasNoProgrammingQuestions = programmingQuestions.length === 0;

// Load all tabs if data is loaded, otherwise fall back to current assessment tab.
const loadedTabs = tabs ?? watch('tabs');
Expand Down Expand Up @@ -834,7 +829,6 @@ const AssessmentForm = (props: AssessmentFormProps): JSX.Element => {
</Section>
)}

{/*
{editing && (
<Section
sticksToNavbar
Expand All @@ -849,17 +843,21 @@ const AssessmentForm = (props: AssessmentFormProps): JSX.Element => {
<LiveFeedbackToggleButton
assessmentIds={[assessmentId]}
for={title}
hideChipIndicator
isCourseCodaveriEnabled={isCourseCodaveriEnabled}
isSpecificAssessment
/>
<div>
<Typography className="mt-3" variant="body1">
{t(translations.toggleLiveFeedbackDescription, {
enabled:
hasNoProgrammingQuestions || isSomeLiveFeedbackEnabled,
})}
{t(translations.toggleLiveFeedbackDescription)}
</Typography>
{hasNoProgrammingQuestions && (
<InfoLabel label={t(translations.noProgrammingQuestion)} />
{(hasNoProgrammingQuestions || !isCourseCodaveriEnabled) && (
<InfoLabel
label={
!isCourseCodaveriEnabled
? t(translations.isCourseCodaveriDisabled)
: t(translations.noProgrammingQuestion)
}
/>
)}
</div>
</div>
Expand All @@ -880,7 +878,7 @@ const AssessmentForm = (props: AssessmentFormProps): JSX.Element => {
</List>
)}
</Section>
)} */}
)}
</form>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ const translations = defineMessages({
defaultMessage:
'Enable live feedback feature for all programming questions',
},
isCourseCodaveriDisabled: {
id: 'course.assessment.AssessmentForm.isCourseCodaveriDisabled',
defaultMessage:
'Please contact the course manager or owner to enable Codaveri Evaluator\
Component in Course Settings',
},
noProgrammingQuestion: {
id: 'course.assessment.AssessmentForm.noProgrammingQuestion',
defaultMessage:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface AssessmentFormProps
initialValues?;
isKoditsuExamEnabled: boolean;
isQuestionsValidForKoditsu: boolean;
isCourseCodaveriEnabled?: boolean;
disabled?: boolean;
showPersonalizedTimelineFeatures?: boolean;
randomizationAllowed?: boolean;
Expand Down
Loading