add Studio base URL to configuration and add Proctored Exam Settings component (#4)

This commit is contained in:
Michael Roytman
2020-07-14 14:24:30 -04:00
committed by GitHub
parent fe6a26dde9
commit 500eba661e
8 changed files with 7666 additions and 6257 deletions

View File

@@ -9,6 +9,7 @@ LMS_BASE_URL='http://localhost:18000'
LOGIN_URL='http://localhost:18000/login'
LOGOUT_URL='http://localhost:18000/logout'
MARKETING_SITE_BASE_URL='http://localhost:18000'
STUDIO_BASE_URL='http://localhost:18010'
ORDER_HISTORY_URL='localhost:1996/orders'
PORT=2001
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'

View File

@@ -7,6 +7,7 @@ LANGUAGE_PREFERENCE_COOKIE_NAME='openedx-language-preference'
LMS_BASE_URL='http://localhost:18000'
LOGIN_URL='http://localhost:18000/login'
LOGOUT_URL='http://localhost:18000/logout'
STUDIO_BASE_URL='http://localhost:18010'
MARKETING_SITE_BASE_URL='http://localhost:18000'
ORDER_HISTORY_URL='localhost:1996/orders'
PORT=2001

View File

@@ -1,3 +1,12 @@
const { createConfig } = require('@edx/frontend-build');
module.exports = createConfig('eslint');
module.exports = createConfig('eslint',
{
"rules": {
"jsx-a11y/label-has-associated-control": [ 2, {
"controlComponents": ["Input"],
}],
}
}
);

13727
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,7 @@
"dependencies": {
"@edx/frontend-component-footer": "10.0.9",
"@edx/frontend-component-header": "2.0.5",
"@edx/frontend-platform": "1.1.14",
"@edx/frontend-platform": "1.5.2",
"@edx/paragon": "7.2.1",
"@fortawesome/fontawesome-svg-core": "1.2.28",
"@fortawesome/free-brands-svg-icons": "5.11.2",

View File

@@ -0,0 +1,18 @@
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getConfig, ensureConfig } from '@edx/frontend-platform';
ensureConfig([
'STUDIO_BASE_URL',
], 'Studio API service');
const studioBaseUrl = getConfig().STUDIO_BASE_URL;
class StudioApiService {
static getProctoredExamSettingsData(courseID) {
const apiClient = getAuthenticatedHttpClient();
const url = `${studioBaseUrl}/api/contentstore/v1/proctored_exam_settings/${courseID}`;
return apiClient.get(url);
}
}
export default StudioApiService;

View File

@@ -6,12 +6,14 @@ import {
import { AppProvider, ErrorPage } from '@edx/frontend-platform/react';
import React from 'react';
import ReactDOM from 'react-dom';
import { Route, Switch } from 'react-router-dom';
import Header, { messages as headerMessages } from '@edx/frontend-component-header';
import Footer, { messages as footerMessages } from '@edx/frontend-component-footer';
import appMessages from './i18n';
import ExamplePage from './example/ExamplePage';
import ProctoredExamSettings from './proctored-exam-settings/ProctoredExamSettings';
import './index.scss';
import './assets/favicon.ico';
@@ -20,7 +22,14 @@ subscribe(APP_READY, () => {
ReactDOM.render(
<AppProvider>
<Header />
<ExamplePage />
<Switch>
<Route path="/proctored-exam-settings">
<ProctoredExamSettings />
</Route>
<Route path="/example">
<ExamplePage />
</Route>
</Switch>
<Footer />
</AppProvider>,
document.getElementById('root'),
@@ -37,4 +46,5 @@ initialize({
headerMessages,
footerMessages,
],
requireAuthenticatedUser: true,
});

View File

@@ -0,0 +1,151 @@
import React, { useState, useEffect } from 'react';
import {
Button, CheckBox, Input, ValidationFormGroup,
} from '@edx/paragon';
import StudioApiService from '../data/services/StudioApiService';
function ExamSettings() {
const [enableProctoredExams, setEnableProctoredExams] = useState(true);
const [allowOptingOut, setAllowOptingOut] = useState(false);
const [proctoringProvider, setProctoringProvider] = useState('');
const [availableProctoringProviders, setAvailableProctoringProviders] = useState([]);
// TODO: we'll probably want to hide this field when proctortrack is not selected; currently,
// this causes some errors in the browser console
const [proctortrackEscalationEmail, setProctortrackEscalationEmail] = useState(null);
const [createZendeskTickets, setCreateZendeskTickets] = useState(false);
function onEnableProctoredExamsChange(event) {
setEnableProctoredExams(event);
}
function onAllowOptingOutChange(event) {
setAllowOptingOut(event);
}
function onCreateZendeskTicketsChange(event) {
setAllowOptingOut(event);
}
function onProctoringProviderChange(event) {
setProctoringProvider(event.target.value);
}
function onProctortrackEscalationEmailChange(event) {
setProctortrackEscalationEmail(event.target.value);
}
function onButtonClick() {
// TODO: implement POST
}
function getProctoringProviderOptions(providers) {
return providers.reduce(
(accumulator, currentValue) => {
accumulator.push({ value: currentValue, label: currentValue }); return accumulator;
}, [],
);
}
useEffect(
() => {
StudioApiService.getProctoredExamSettingsData('course-v1:edX+DemoX+Demo_Course')
.then(
response => {
const proctoredExamSettings = response.data.proctored_exam_settings;
setEnableProctoredExams(proctoredExamSettings.enable_proctored_exams);
setAllowOptingOut(proctoredExamSettings.allow_proctoring_opt_out);
setProctoringProvider(proctoredExamSettings.proctoring_provider);
setAvailableProctoringProviders(response.data.available_proctoring_providers);
setProctortrackEscalationEmail(proctoredExamSettings.proctoring_escalation_email);
setCreateZendeskTickets(proctoredExamSettings.create_zendesk_tickets);
},
);
// TODO: handle error
}, [],
);
return (
<div className="container">
<h2 className="mb-1">
Proctored Exam Settings
</h2>
<ValidationFormGroup
for="enableProctoredExams"
helpText="If checked, proctored exams are enabled in your course."
>
<CheckBox
id="enableProctoredExams"
name="enable_proctored_exams"
label="Enable Proctored Exams"
checked={enableProctoredExams}
onChange={onEnableProctoredExamsChange}
/>
</ValidationFormGroup>
<ValidationFormGroup
for="allowingOptingOut"
helpText="If checked, learners can choose to take proctored exams without proctoring. If not checked, all learners must take the exam with proctoring."
>
<CheckBox
id="allowingOptingOut"
name="allow_opting_out"
label="Allow Opting Out of Proctored Exams"
checked={allowOptingOut}
onChange={onAllowOptingOutChange}
/>
</ValidationFormGroup>
<ValidationFormGroup
for="proctoringProvider"
helpText="Select the proctoring provider you want to use for this course run."
>
<label htmlFor="proctoringProvider">Proctoring Provider</label>
<Input
type="select"
id="proctoringProvider"
name="proctoring_provider"
options={getProctoringProviderOptions(availableProctoringProviders)}
value={proctoringProvider}
onChange={onProctoringProviderChange}
/>
</ValidationFormGroup>
<ValidationFormGroup
for="proctortrackEscalationEmail"
helpText="Required if 'proctortrack' is selected as your proctoring provider. Enter an email address to be contacted by the support team whenever there are escalations (e.g. appeals, delayed reviews, etc.)."
>
<label htmlFor="proctortrackEscalationEmail">Proctortrack Escalation Email</label>
<Input
type="text"
id="proctortrackEscalationEmail"
name="proctortrack_escalation_email"
value={proctortrackEscalationEmail}
onChange={onProctortrackEscalationEmailChange}
/>
</ValidationFormGroup>
<ValidationFormGroup
for="createZendeskTickets"
helpText="If checked, a Zendesk ticket will be created for suspicious attempts."
>
<CheckBox
id="createZendeskTickets"
name="create_zendesk_tickets"
label="Create Zendesk Tickets For Suspicious Exam Attempts"
checked={createZendeskTickets}
onChange={onCreateZendeskTicketsChange}
/>
</ValidationFormGroup>
<Button
className="btn-primary mb-3"
onClick={onButtonClick}
>
Submit
</Button>
</div>
);
}
ExamSettings.propTypes = {};
ExamSettings.defaultProps = {};
export default ExamSettings;