feat: Created Course Team (#564)
This commit is contained in:
@@ -13,6 +13,7 @@ import FilesAndUploads from './files-and-uploads';
|
||||
import { AdvancedSettings } from './advanced-settings';
|
||||
import ScheduleAndDetails from './schedule-and-details';
|
||||
import { GradingSettings } from './grading-settings';
|
||||
import CourseTeam from './course-team/CourseTeam';
|
||||
|
||||
/**
|
||||
* As of this writing, these routes are mounted at a path prefixed with the following:
|
||||
@@ -94,10 +95,7 @@ const CourseAuthoringRoutes = ({ courseId }) => {
|
||||
<GradingSettings courseId={courseId} />
|
||||
</PageRoute>
|
||||
<PageRoute path={`${path}/course_team`}>
|
||||
{process.env.ENABLE_NEW_COURSE_TEAM_PAGE === 'true'
|
||||
&& (
|
||||
<Placeholder />
|
||||
)}
|
||||
<CourseTeam courseId={courseId} />
|
||||
</PageRoute>
|
||||
<PageRoute path={`${path}/settings/advanced`}>
|
||||
<AdvancedSettings courseId={courseId} />
|
||||
|
||||
@@ -7,3 +7,13 @@ export const STATEFUL_BUTTON_STATES = {
|
||||
pending: 'pending',
|
||||
default: 'default',
|
||||
};
|
||||
|
||||
export const USER_ROLES = {
|
||||
admin: 'instructor',
|
||||
staff: 'staff',
|
||||
};
|
||||
|
||||
export const BADGE_STATES = {
|
||||
danger: 'danger',
|
||||
secondary: 'secondary',
|
||||
};
|
||||
|
||||
163
src/course-team/CourseTeam.jsx
Normal file
163
src/course-team/CourseTeam.jsx
Normal file
@@ -0,0 +1,163 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl, injectIntl } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Button,
|
||||
Container,
|
||||
Layout,
|
||||
} from '@edx/paragon';
|
||||
import { Add as IconAdd } from '@edx/paragon/icons';
|
||||
|
||||
import InternetConnectionAlert from '../generic/internet-connection-alert';
|
||||
import SubHeader from '../generic/sub-header/SubHeader';
|
||||
import { USER_ROLES } from '../constants';
|
||||
import messages from './messages';
|
||||
import CourseTeamSideBar from './course-team-sidebar/CourseTeamSidebar';
|
||||
import AddUserForm from './add-user-form/AddUserForm';
|
||||
import AddTeamMember from './add-team-member/AddTeamMember';
|
||||
import CourseTeamMember from './course-team-member/CourseTeamMember';
|
||||
import InfoModal from './info-modal/InfoModal';
|
||||
import { useCourseTeam } from './hooks';
|
||||
|
||||
const CourseTeam = ({ courseId }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const {
|
||||
modalType,
|
||||
errorMessage,
|
||||
courseName,
|
||||
currentEmail,
|
||||
courseTeamUsers,
|
||||
currentUserEmail,
|
||||
isLoading,
|
||||
isSingleAdmin,
|
||||
isFormVisible,
|
||||
isQueryPending,
|
||||
isAllowActions,
|
||||
isInfoModalOpen,
|
||||
isOwnershipHint,
|
||||
isShowAddTeamMember,
|
||||
isShowInitialSidebar,
|
||||
isShowUserFilledSidebar,
|
||||
isInternetConnectionAlertFailed,
|
||||
openForm,
|
||||
hideForm,
|
||||
closeInfoModal,
|
||||
handleAddUserSubmit,
|
||||
handleOpenDeleteModal,
|
||||
handleDeleteUserSubmit,
|
||||
handleChangeRoleUserSubmit,
|
||||
handleInternetConnectionFailed,
|
||||
} = useCourseTeam({ intl, courseId });
|
||||
|
||||
if (isLoading) {
|
||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container size="xl" className="m-4">
|
||||
<section className="course-team-container mb-4">
|
||||
<Layout
|
||||
lg={[{ span: 9 }, { span: 3 }]}
|
||||
md={[{ span: 9 }, { span: 3 }]}
|
||||
sm={[{ span: 9 }, { span: 3 }]}
|
||||
xs={[{ span: 9 }, { span: 3 }]}
|
||||
xl={[{ span: 9 }, { span: 3 }]}
|
||||
>
|
||||
<Layout.Element>
|
||||
<article>
|
||||
<div>
|
||||
<SubHeader
|
||||
title={intl.formatMessage(messages.headingTitle)}
|
||||
subtitle={intl.formatMessage(messages.headingSubtitle)}
|
||||
headerActions={isAllowActions && (
|
||||
<Button
|
||||
variant="outline-success"
|
||||
iconBefore={IconAdd}
|
||||
size="sm"
|
||||
onClick={openForm}
|
||||
disabled={isFormVisible}
|
||||
>
|
||||
{intl.formatMessage(messages.addNewMemberButton)}
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
<section className="course-team-section">
|
||||
<div className="members-container">
|
||||
{isFormVisible && (
|
||||
<AddUserForm
|
||||
onSubmit={handleAddUserSubmit}
|
||||
onCancel={hideForm}
|
||||
/>
|
||||
)}
|
||||
{courseTeamUsers.length ? courseTeamUsers.map(({ username, role, email }) => (
|
||||
<CourseTeamMember
|
||||
key={email}
|
||||
userName={username}
|
||||
role={role}
|
||||
email={email}
|
||||
currentUserEmail={currentUserEmail || ''}
|
||||
isAllowActions={isAllowActions}
|
||||
isHideActions={role === USER_ROLES.admin && isSingleAdmin}
|
||||
onChangeRole={handleChangeRoleUserSubmit}
|
||||
onDelete={handleOpenDeleteModal}
|
||||
/>
|
||||
)) : null}
|
||||
{isShowAddTeamMember && (
|
||||
<AddTeamMember
|
||||
onFormOpen={openForm}
|
||||
isButtonDisable={isFormVisible}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{isShowInitialSidebar && (
|
||||
<div className="sidebar-container">
|
||||
<CourseTeamSideBar
|
||||
courseId={courseId}
|
||||
isOwnershipHint={isOwnershipHint}
|
||||
isShowInitialSidebar={isShowInitialSidebar}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<InfoModal
|
||||
isOpen={isInfoModalOpen}
|
||||
close={closeInfoModal}
|
||||
currentEmail={currentEmail}
|
||||
errorMessage={errorMessage}
|
||||
courseName={courseName}
|
||||
modalType={modalType}
|
||||
onDeleteSubmit={handleDeleteUserSubmit}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
</Layout.Element>
|
||||
<Layout.Element>
|
||||
{isShowUserFilledSidebar && (
|
||||
<CourseTeamSideBar
|
||||
courseId={courseId}
|
||||
isOwnershipHint={isOwnershipHint}
|
||||
/>
|
||||
)}
|
||||
</Layout.Element>
|
||||
</Layout>
|
||||
</section>
|
||||
</Container>
|
||||
<div className="alert-toast">
|
||||
<InternetConnectionAlert
|
||||
isFailed={isInternetConnectionAlertFailed}
|
||||
isQueryPending={isQueryPending}
|
||||
onInternetConnectionFailed={handleInternetConnectionFailed}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
CourseTeam.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(CourseTeam);
|
||||
23
src/course-team/CourseTeam.scss
Normal file
23
src/course-team/CourseTeam.scss
Normal file
@@ -0,0 +1,23 @@
|
||||
@import "./course-team-sidebar/CourseTeamSidebar";
|
||||
@import "./add-user-form/AddUserForm";
|
||||
@import "./add-team-member/AddTeamMember";
|
||||
@import "./course-team-member/CourseTeamMember";
|
||||
|
||||
.course-team-section {
|
||||
.sidebar-container {
|
||||
width: 30%;
|
||||
|
||||
.help-sidebar {
|
||||
margin-top: 0;
|
||||
|
||||
hr {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.members-container {
|
||||
flex-grow: 1;
|
||||
padding-top: 1.25rem;
|
||||
}
|
||||
}
|
||||
222
src/course-team/CourseTeam.test.jsx
Normal file
222
src/course-team/CourseTeam.test.jsx
Normal file
@@ -0,0 +1,222 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
render,
|
||||
fireEvent,
|
||||
cleanup,
|
||||
waitFor,
|
||||
} from '@testing-library/react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import initializeStore from '../store';
|
||||
import { courseTeamMock, courseTeamWithOneUser, courseTeamWithoutUsers } from './__mocks__';
|
||||
import { getCourseTeamApiUrl, updateCourseTeamUserApiUrl } from './data/api';
|
||||
import CourseTeam from './CourseTeam';
|
||||
import messages from './messages';
|
||||
import { USER_ROLES } from '../constants';
|
||||
import { executeThunk } from '../utils';
|
||||
import { changeRoleTeamUserQuery, deleteCourseTeamQuery } from './data/thunk';
|
||||
|
||||
let axiosMock;
|
||||
let store;
|
||||
const mockPathname = '/foo-bar';
|
||||
const courseId = '123';
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useLocation: () => ({
|
||||
pathname: mockPathname,
|
||||
}),
|
||||
}));
|
||||
|
||||
const RootWrapper = () => (
|
||||
<AppProvider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<CourseTeam courseId={courseId} />
|
||||
</IntlProvider>
|
||||
</AppProvider>
|
||||
);
|
||||
|
||||
describe('<CourseTeam />', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
|
||||
store = initializeStore();
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
});
|
||||
|
||||
it('render CourseTeam component with 3 team members correctly', async () => {
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, courseTeamMock);
|
||||
|
||||
const {
|
||||
getByText, getByRole, getByTestId, queryAllByTestId,
|
||||
} = render(<RootWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.headingSubtitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByRole('button', { name: messages.addNewMemberButton.defaultMessage })).toBeInTheDocument();
|
||||
expect(getByTestId('course-team-sidebar')).toBeInTheDocument();
|
||||
expect(queryAllByTestId('course-team-member')).toHaveLength(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('render CourseTeam component with 1 team member correctly', async () => {
|
||||
cleanup();
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, courseTeamWithOneUser);
|
||||
|
||||
const {
|
||||
getByText, getByRole, getByTestId, getAllByTestId,
|
||||
} = render(<RootWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.headingSubtitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByRole('button', { name: messages.addNewMemberButton.defaultMessage })).toBeInTheDocument();
|
||||
expect(getByTestId('course-team-sidebar')).toBeInTheDocument();
|
||||
expect(getAllByTestId('course-team-member')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('render CourseTeam component without team member correctly', async () => {
|
||||
cleanup();
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, courseTeamWithoutUsers);
|
||||
|
||||
const {
|
||||
getByText, getByRole, getByTestId, queryAllByTestId,
|
||||
} = render(<RootWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.headingSubtitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByRole('button', { name: messages.addNewMemberButton.defaultMessage })).toBeInTheDocument();
|
||||
expect(getByTestId('course-team-sidebar__initial')).toBeInTheDocument();
|
||||
expect(queryAllByTestId('course-team-member')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('render CourseTeam component with initial sidebar correctly', async () => {
|
||||
cleanup();
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, courseTeamWithoutUsers);
|
||||
|
||||
const { getByTestId, queryByTestId } = render(<RootWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('course-team-sidebar__initial')).toBeInTheDocument();
|
||||
expect(queryByTestId('course-team-sidebar')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('render CourseTeam component without initial sidebar correctly', async () => {
|
||||
cleanup();
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, courseTeamMock);
|
||||
|
||||
const { getByTestId, queryByTestId } = render(<RootWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByTestId('course-team-sidebar__initial')).not.toBeInTheDocument();
|
||||
expect(getByTestId('course-team-sidebar')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('displays AddUserForm when clicking the "Add New Member" button', async () => {
|
||||
cleanup();
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, courseTeamWithOneUser);
|
||||
|
||||
const { getByRole, queryByTestId } = render(<RootWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByTestId('add-user-form')).not.toBeInTheDocument();
|
||||
const addButton = getByRole('button', { name: messages.addNewMemberButton.defaultMessage });
|
||||
fireEvent.click(addButton);
|
||||
expect(queryByTestId('add-user-form')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('displays AddUserForm when clicking the "Add a New Team member" button', async () => {
|
||||
cleanup();
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, courseTeamWithOneUser);
|
||||
|
||||
const { getByRole, queryByTestId } = render(<RootWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByTestId('add-user-form')).not.toBeInTheDocument();
|
||||
const addButton = getByRole('button', { name: 'Add a new team member' });
|
||||
fireEvent.click(addButton);
|
||||
expect(queryByTestId('add-user-form')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('not displays "Add New Member" and AddTeamMember component when isAllowActions is false', async () => {
|
||||
cleanup();
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, {
|
||||
...courseTeamWithOneUser,
|
||||
allowActions: false,
|
||||
});
|
||||
|
||||
const { queryByRole, queryByTestId } = render(<RootWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByRole('button', { name: messages.addNewMemberButton.defaultMessage })).not.toBeInTheDocument();
|
||||
expect(queryByTestId('add-team-member')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delete user', async () => {
|
||||
cleanup();
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, courseTeamMock);
|
||||
|
||||
const { queryByText } = render(<RootWrapper />);
|
||||
|
||||
axiosMock
|
||||
.onDelete(updateCourseTeamUserApiUrl(courseId, 'staff@example.com'))
|
||||
.reply(200);
|
||||
|
||||
await executeThunk(deleteCourseTeamQuery(courseId, 'staff@example.com'), store.dispatch);
|
||||
expect(queryByText('staff@example.com')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should change role user', async () => {
|
||||
cleanup();
|
||||
axiosMock
|
||||
.onGet(getCourseTeamApiUrl(courseId))
|
||||
.reply(200, courseTeamMock);
|
||||
|
||||
const { getAllByText } = render(<RootWrapper />);
|
||||
|
||||
axiosMock
|
||||
.onPut(updateCourseTeamUserApiUrl(courseId, 'staff@example.com', { role: USER_ROLES.admin }))
|
||||
.reply(200, { role: USER_ROLES.admin });
|
||||
|
||||
await executeThunk(changeRoleTeamUserQuery(courseId, 'staff@example.com', { role: USER_ROLES.admin }), store.dispatch);
|
||||
expect(getAllByText('Admin')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
24
src/course-team/__mocks__/courseTeam.js
Normal file
24
src/course-team/__mocks__/courseTeam.js
Normal file
@@ -0,0 +1,24 @@
|
||||
module.exports = {
|
||||
showTransferOwnershipHint: true,
|
||||
users: [
|
||||
{
|
||||
email: 'staff@example.com',
|
||||
id: '2',
|
||||
role: 'staff',
|
||||
username: 'Staff_Name',
|
||||
},
|
||||
{
|
||||
email: 'audit@example.com',
|
||||
id: '3',
|
||||
role: 'staff',
|
||||
username: 'Audit_Name',
|
||||
},
|
||||
{
|
||||
email: 'vladislav.keblysh@raccoongang.com',
|
||||
id: '1',
|
||||
role: 'instructor',
|
||||
username: 'Vladislav_Keblysh',
|
||||
},
|
||||
],
|
||||
allowActions: true,
|
||||
};
|
||||
12
src/course-team/__mocks__/courseTeamWithOneUser.js
Normal file
12
src/course-team/__mocks__/courseTeamWithOneUser.js
Normal file
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
showTransferOwnershipHint: true,
|
||||
users: [
|
||||
{
|
||||
email: 'staff@example.com',
|
||||
id: '2',
|
||||
role: 'staff',
|
||||
username: 'Staff_Name',
|
||||
},
|
||||
],
|
||||
allowActions: true,
|
||||
};
|
||||
5
src/course-team/__mocks__/courseTeamWithoutUsers.js
Normal file
5
src/course-team/__mocks__/courseTeamWithoutUsers.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
showTransferOwnershipHint: true,
|
||||
users: [],
|
||||
allowActions: true,
|
||||
};
|
||||
3
src/course-team/__mocks__/index.js
Normal file
3
src/course-team/__mocks__/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as courseTeamMock } from './courseTeam';
|
||||
export { default as courseTeamWithOneUser } from './courseTeamWithOneUser';
|
||||
export { default as courseTeamWithoutUsers } from './courseTeamWithoutUsers';
|
||||
39
src/course-team/add-team-member/AddTeamMember.jsx
Normal file
39
src/course-team/add-team-member/AddTeamMember.jsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Add as IconAdd } from '@edx/paragon/icons';
|
||||
import { Button } from '@edx/paragon';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
const AddTeamMember = ({ onFormOpen, isButtonDisable }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<div className="add-team-member bg-gray-100" data-testid="add-team-member">
|
||||
<div className="add-team-member-info">
|
||||
<h3 className="add-team-member-title font-weight-bold">{intl.formatMessage(messages.title)}</h3>
|
||||
<span className="text-gray-500 small">{intl.formatMessage(messages.description)}</span>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline-success"
|
||||
iconBefore={IconAdd}
|
||||
onClick={onFormOpen}
|
||||
disabled={isButtonDisable}
|
||||
>
|
||||
{intl.formatMessage(messages.button)}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
AddTeamMember.propTypes = {
|
||||
onFormOpen: PropTypes.func.isRequired,
|
||||
isButtonDisable: PropTypes.bool,
|
||||
};
|
||||
|
||||
AddTeamMember.defaultProps = {
|
||||
isButtonDisable: false,
|
||||
};
|
||||
|
||||
export default AddTeamMember;
|
||||
17
src/course-team/add-team-member/AddTeamMember.scss
Normal file
17
src/course-team/add-team-member/AddTeamMember.scss
Normal file
@@ -0,0 +1,17 @@
|
||||
.add-team-member {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border: .0625rem solid $gray-200;
|
||||
border-radius: .375rem;
|
||||
box-shadow: inset inset 0 1px .125rem 1px $gray-200;
|
||||
padding: 1.25rem 1.875rem;
|
||||
|
||||
.add-team-member-info {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.add-team-member-title {
|
||||
font-size: $spacer;
|
||||
}
|
||||
}
|
||||
46
src/course-team/add-team-member/AddTeamMember.test.jsx
Normal file
46
src/course-team/add-team-member/AddTeamMember.test.jsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import AddTeamMember from './AddTeamMember';
|
||||
import messages from './messages';
|
||||
|
||||
const onFormOpenMock = jest.fn();
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<IntlProvider locale="en">
|
||||
<AddTeamMember onFormOpen={onFormOpenMock} {...props} />
|
||||
</IntlProvider>,
|
||||
);
|
||||
|
||||
describe('<AddTeamMember />', () => {
|
||||
it('render AddTeamMember component correctly', () => {
|
||||
const { getByText, getByRole } = renderComponent();
|
||||
|
||||
expect(getByText(messages.title.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.description.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByRole('button', { name: messages.button.defaultMessage })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onFormOpen when the button is clicked', () => {
|
||||
const { getByText } = renderComponent();
|
||||
|
||||
const addButton = getByText(messages.button.defaultMessage);
|
||||
fireEvent.click(addButton);
|
||||
expect(onFormOpenMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('"Add a New Team member" button is disabled when isButtonDisable is true', () => {
|
||||
const { getByRole } = renderComponent({ isButtonDisable: true });
|
||||
|
||||
const addButton = getByRole('button', { name: messages.button.defaultMessage });
|
||||
expect(addButton).toBeDisabled();
|
||||
});
|
||||
|
||||
it('"Add a New Team member" button is not disabled when isButtonDisable is false', () => {
|
||||
const { getByRole } = renderComponent();
|
||||
|
||||
const addButton = getByRole('button', { name: messages.button.defaultMessage });
|
||||
expect(addButton).not.toBeDisabled();
|
||||
});
|
||||
});
|
||||
18
src/course-team/add-team-member/messages.js
Normal file
18
src/course-team/add-team-member/messages.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'course-authoring.course-team.add-team-member.title',
|
||||
defaultMessage: 'Add team members to this course',
|
||||
},
|
||||
description: {
|
||||
id: 'course-authoring.course-team.add-team-member.description',
|
||||
defaultMessage: 'Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.',
|
||||
},
|
||||
button: {
|
||||
id: 'course-authoring.course-team.add-team-member.button',
|
||||
defaultMessage: 'Add a new team member',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
66
src/course-team/add-user-form/AddUserForm.jsx
Normal file
66
src/course-team/add-user-form/AddUserForm.jsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
ActionRow,
|
||||
} from '@edx/paragon';
|
||||
import { Formik } from 'formik';
|
||||
|
||||
import messages from './messages';
|
||||
import FormikControl from '../../generic/FormikControl';
|
||||
import { EXAMPLE_USER_EMAIL } from '../constants';
|
||||
|
||||
const AddUserForm = ({ onSubmit, onCancel }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<div className="add-user-form" data-testid="add-user-form">
|
||||
<Formik
|
||||
initialValues={{ email: '' }}
|
||||
onSubmit={onSubmit}
|
||||
validateOnBlur
|
||||
>
|
||||
{({ handleSubmit, values }) => (
|
||||
<>
|
||||
<Form.Group size="sm" className="form-field">
|
||||
<h3 className="form-title">{intl.formatMessage(messages.formTitle)}</h3>
|
||||
<Form.Label size="sm" className="form-label font-weight-bold">
|
||||
{intl.formatMessage(messages.formLabel)}
|
||||
</Form.Label>
|
||||
<FormikControl
|
||||
name="email"
|
||||
value={values.email}
|
||||
placeholder={intl.formatMessage(messages.formPlaceholder, { email: EXAMPLE_USER_EMAIL })}
|
||||
/>
|
||||
<Form.Control.Feedback className="form-helper-text">
|
||||
{intl.formatMessage(messages.formHelperText)}
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
<ActionRow>
|
||||
<Button variant="tertiary" size="sm" onClick={onCancel}>
|
||||
{intl.formatMessage(messages.cancelButton)}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleSubmit}
|
||||
disabled={!values.email.length}
|
||||
type="submit"
|
||||
>
|
||||
{intl.formatMessage(messages.addUserButton)}
|
||||
</Button>
|
||||
</ActionRow>
|
||||
</>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
AddUserForm.propTypes = {
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
onCancel: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default AddUserForm;
|
||||
42
src/course-team/add-user-form/AddUserForm.scss
Normal file
42
src/course-team/add-user-form/AddUserForm.scss
Normal file
@@ -0,0 +1,42 @@
|
||||
.add-user-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: .0625rem solid $gray-200;
|
||||
border-radius: .375rem;
|
||||
box-shadow: 0 1px 1px $gray-200;
|
||||
margin-bottom: 1.25rem;
|
||||
background-color: $white;
|
||||
|
||||
.form-title {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1.875rem;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
padding: 1.25rem 1.875rem;
|
||||
margin-bottom: $spacer;
|
||||
|
||||
.pgn__form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.form-label {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
margin-left: .3125rem;
|
||||
content: "*";
|
||||
}
|
||||
}
|
||||
|
||||
.form-helper-text {
|
||||
font-size: $font-size-xs;
|
||||
}
|
||||
|
||||
.pgn__action-row {
|
||||
padding: $spacer 1.875rem;
|
||||
border-top: .0625rem solid $gray-200;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
128
src/course-team/add-user-form/AddUserForm.test.jsx
Normal file
128
src/course-team/add-user-form/AddUserForm.test.jsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
render,
|
||||
fireEvent,
|
||||
act,
|
||||
waitFor,
|
||||
} from '@testing-library/react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { EXAMPLE_USER_EMAIL } from '../constants';
|
||||
import initializeStore from '../../store';
|
||||
import { USER_ROLES } from '../../constants';
|
||||
import { updateCourseTeamUserApiUrl } from '../data/api';
|
||||
import { createCourseTeamQuery } from '../data/thunk';
|
||||
import { executeThunk } from '../../utils';
|
||||
import AddUserForm from './AddUserForm';
|
||||
import messages from './messages';
|
||||
|
||||
let axiosMock;
|
||||
let store;
|
||||
const mockPathname = '/foo-bar';
|
||||
const courseId = '123';
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useLocation: () => ({
|
||||
pathname: mockPathname,
|
||||
}),
|
||||
}));
|
||||
|
||||
const onSubmitMock = jest.fn();
|
||||
const onCancelMock = jest.fn();
|
||||
|
||||
const RootWrapper = () => (
|
||||
<AppProvider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<AddUserForm
|
||||
onSubmit={onSubmitMock}
|
||||
onCancel={onCancelMock}
|
||||
/>
|
||||
</IntlProvider>
|
||||
</AppProvider>
|
||||
);
|
||||
|
||||
describe('<AddUserForm />', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
|
||||
store = initializeStore();
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
});
|
||||
|
||||
it('render AddUserForm component correctly', () => {
|
||||
const { getByText, getByPlaceholderText } = render(<RootWrapper />);
|
||||
|
||||
expect(getByText(messages.formTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.formLabel.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByPlaceholderText(messages.formPlaceholder.defaultMessage
|
||||
.replace('{email}', EXAMPLE_USER_EMAIL))).toBeInTheDocument();
|
||||
expect(getByText(messages.cancelButton.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.addUserButton.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onSubmit when the "Add User" button is clicked with a valid email', async () => {
|
||||
const { getByPlaceholderText, getByRole } = render(<RootWrapper />);
|
||||
|
||||
const emailInput = getByPlaceholderText(messages.formPlaceholder.defaultMessage.replace('{email}', EXAMPLE_USER_EMAIL));
|
||||
const addUserButton = getByRole('button', { name: messages.addUserButton.defaultMessage });
|
||||
|
||||
fireEvent.change(emailInput, { target: { value: EXAMPLE_USER_EMAIL } });
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(addUserButton);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onSubmitMock).toHaveBeenCalledTimes(1);
|
||||
expect(onSubmitMock).toHaveBeenCalledWith(
|
||||
{ email: EXAMPLE_USER_EMAIL },
|
||||
expect.objectContaining({ submitForm: expect.any(Function) }),
|
||||
);
|
||||
});
|
||||
|
||||
axiosMock
|
||||
.onPost(updateCourseTeamUserApiUrl(courseId, EXAMPLE_USER_EMAIL), { role: USER_ROLES.staff })
|
||||
.reply(200, { role: USER_ROLES.staff });
|
||||
|
||||
await executeThunk(createCourseTeamQuery(courseId, EXAMPLE_USER_EMAIL), store.dispatch);
|
||||
});
|
||||
|
||||
it('calls onCancel when the "Cancel" button is clicked', () => {
|
||||
const { getByText } = render(<RootWrapper />);
|
||||
|
||||
const cancelButton = getByText(messages.cancelButton.defaultMessage);
|
||||
fireEvent.click(cancelButton);
|
||||
expect(onCancelMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('"Add User" button is disabled when the email input field is empty', () => {
|
||||
const { getByText } = render(<RootWrapper />);
|
||||
|
||||
const addUserButton = getByText(messages.addUserButton.defaultMessage);
|
||||
expect(addUserButton).toBeDisabled();
|
||||
});
|
||||
|
||||
it('"Add User" button is not disabled when the email input field is not empty', () => {
|
||||
const { getByPlaceholderText, getByText } = render(<RootWrapper />);
|
||||
|
||||
const emailInput = getByPlaceholderText(
|
||||
messages.formPlaceholder.defaultMessage.replace('{email}', EXAMPLE_USER_EMAIL),
|
||||
);
|
||||
const addUserButton = getByText(messages.addUserButton.defaultMessage);
|
||||
|
||||
fireEvent.change(emailInput, { target: { value: 'user@example.com' } });
|
||||
expect(addUserButton).not.toBeDisabled();
|
||||
});
|
||||
});
|
||||
31
src/course-team/add-user-form/messages.js
Normal file
31
src/course-team/add-user-form/messages.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
formTitle: {
|
||||
id: 'course-authoring.course-team.form.title',
|
||||
defaultMessage: 'Add a user to your course\'s team',
|
||||
},
|
||||
formLabel: {
|
||||
id: 'course-authoring.course-team.form.label',
|
||||
defaultMessage: 'User\'s email address',
|
||||
},
|
||||
formPlaceholder: {
|
||||
id: 'course-authoring.course-team.form.placeholder',
|
||||
defaultMessage: 'example: {email}',
|
||||
},
|
||||
formHelperText: {
|
||||
id: 'course-authoring.course-team.form.helperText',
|
||||
defaultMessage: 'Provide the email address of the user you want to add as Staff',
|
||||
},
|
||||
addUserButton: {
|
||||
id: 'course-authoring.course-team.form.button.addUser',
|
||||
defaultMessage: 'Add user',
|
||||
},
|
||||
cancelButton: {
|
||||
id: 'course-authoring.course-team.form.button.cancel',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default messages;
|
||||
7
src/course-team/constants.js
Normal file
7
src/course-team/constants.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export const MODAL_TYPES = {
|
||||
error: 'error',
|
||||
delete: 'delete',
|
||||
warning: 'warning',
|
||||
};
|
||||
|
||||
export const EXAMPLE_USER_EMAIL = 'username@domain.com';
|
||||
78
src/course-team/course-team-member/CourseTeamMember.jsx
Normal file
78
src/course-team/course-team-member/CourseTeamMember.jsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Badge, Button, MailtoLink } from '@edx/paragon';
|
||||
import { DeleteOutline as DeleteOutlineIcon } from '@edx/paragon/icons';
|
||||
|
||||
import messages from './messages';
|
||||
import { USER_ROLES, BADGE_STATES } from '../../constants';
|
||||
|
||||
const CourseTeamMember = ({
|
||||
userName,
|
||||
role,
|
||||
email,
|
||||
onChangeRole,
|
||||
onDelete,
|
||||
currentUserEmail,
|
||||
isHideActions,
|
||||
isAllowActions,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const isAdminRole = role === USER_ROLES.admin;
|
||||
|
||||
return (
|
||||
<div className="course-team-member" data-testid="course-team-member">
|
||||
<div className="member-info">
|
||||
<Badge variant={isAdminRole ? BADGE_STATES.danger : BADGE_STATES.secondary} className="badge-current-user">
|
||||
{isAdminRole
|
||||
? intl.formatMessage(messages.roleAdmin)
|
||||
: intl.formatMessage(messages.roleStaff)}
|
||||
{currentUserEmail === email && (
|
||||
<span className="badge-current-user">{intl.formatMessage(messages.roleYou)}</span>
|
||||
)}
|
||||
</Badge>
|
||||
<span className="member-info-name font-weight-bold">{userName}</span>
|
||||
<MailtoLink to={email}>{email}</MailtoLink>
|
||||
</div>
|
||||
{/* eslint-disable-next-line no-nested-ternary */}
|
||||
{isAllowActions && (
|
||||
!isHideActions ? (
|
||||
<div className="member-actions">
|
||||
<Button
|
||||
variant={isAdminRole ? 'tertiary' : 'primary'}
|
||||
size="sm"
|
||||
onClick={() => onChangeRole(email, isAdminRole ? USER_ROLES.staff : USER_ROLES.admin)}
|
||||
>
|
||||
{isAdminRole ? intl.formatMessage(messages.removeButton) : intl.formatMessage(messages.addButton)}
|
||||
</Button>
|
||||
<Button
|
||||
className="delete-button"
|
||||
variant="tertiary"
|
||||
size="sm"
|
||||
data-testid="delete-button"
|
||||
iconBefore={DeleteOutlineIcon}
|
||||
onClick={() => onDelete(email)}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="member-hint text-right">
|
||||
<span>{intl.formatMessage(messages.hint)}</span>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
CourseTeamMember.propTypes = {
|
||||
userName: PropTypes.string.isRequired,
|
||||
role: PropTypes.string.isRequired,
|
||||
email: PropTypes.string.isRequired,
|
||||
onChangeRole: PropTypes.func.isRequired,
|
||||
onDelete: PropTypes.func.isRequired,
|
||||
currentUserEmail: PropTypes.string.isRequired,
|
||||
isHideActions: PropTypes.bool.isRequired,
|
||||
isAllowActions: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default CourseTeamMember;
|
||||
63
src/course-team/course-team-member/CourseTeamMember.scss
Normal file
63
src/course-team/course-team-member/CourseTeamMember.scss
Normal file
@@ -0,0 +1,63 @@
|
||||
.course-team-container {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.course-team-member {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
padding: 1.563rem 1.875rem 1.25rem;
|
||||
background-color: $white;
|
||||
border: .0625rem solid $gray-200;
|
||||
border-radius: .375rem;
|
||||
box-shadow: 0 1px 1px $gray-200;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.member-info {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.badge {
|
||||
position: absolute;
|
||||
top: -2.25rem;
|
||||
left: -.25rem;
|
||||
}
|
||||
|
||||
.badge-current-user {
|
||||
color: $gray-100;
|
||||
margin-left: .25rem;
|
||||
}
|
||||
|
||||
.member-info-name {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: .25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.member-hint {
|
||||
width: 45%;
|
||||
margin-right: 3.875rem;
|
||||
color: $gray-300;
|
||||
font-size: $font-size-sm;
|
||||
}
|
||||
|
||||
.member-actions {
|
||||
display: flex;
|
||||
gap: $spacer;
|
||||
|
||||
.delete-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
& > span {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
src/course-team/course-team-member/CourseTeamMember.test.jsx
Normal file
91
src/course-team/course-team-member/CourseTeamMember.test.jsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import React from 'react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { USER_ROLES } from '../../constants';
|
||||
import CourseTeamMember from './CourseTeamMember';
|
||||
import messages from './messages';
|
||||
|
||||
const userNameMock = 'User';
|
||||
const emailMock = 'user@example.com';
|
||||
const currentUserEmailMock = 'user@example.com';
|
||||
const onChangeRoleMock = jest.fn();
|
||||
const onDeleteMock = jest.fn();
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<IntlProvider locale="en">
|
||||
<CourseTeamMember
|
||||
userName={userNameMock}
|
||||
email={emailMock}
|
||||
currentUserEmail="some@example.com"
|
||||
onChangeRole={onChangeRoleMock}
|
||||
onDelete={onDeleteMock}
|
||||
isAllowActions
|
||||
isHideActions={false}
|
||||
role={USER_ROLES.admin}
|
||||
{...props}
|
||||
/>
|
||||
</IntlProvider>,
|
||||
);
|
||||
|
||||
describe('<CourseTeamMember />', () => {
|
||||
it('render CourseTeamMember component correctly', () => {
|
||||
const { getByText, getByRole, getByTestId } = renderComponent();
|
||||
|
||||
expect(getByText(userNameMock)).toBeInTheDocument();
|
||||
expect(getByText(emailMock)).toBeInTheDocument();
|
||||
expect(getByRole('button', { name: messages.removeButton.defaultMessage })).toBeInTheDocument();
|
||||
expect(getByTestId('delete-button')).toBeInTheDocument();
|
||||
expect(getByText(messages.roleAdmin.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays correct badge and "You" label for the current user', () => {
|
||||
const { getByText } = renderComponent({
|
||||
role: USER_ROLES.staff,
|
||||
currentUserEmail: currentUserEmailMock,
|
||||
});
|
||||
|
||||
expect(getByText(messages.roleStaff.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.roleYou.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('not displays actions when isAllowActions is false', () => {
|
||||
const { queryByRole, queryByTestId } = renderComponent({
|
||||
role: USER_ROLES.admin,
|
||||
currentUserEmail: currentUserEmailMock,
|
||||
isAllowActions: false,
|
||||
});
|
||||
|
||||
expect(queryByRole('button', { name: messages.removeButton.defaultMessage })).not.toBeInTheDocument();
|
||||
expect(queryByTestId('delete-button')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onChangeRole when the "Add"/"Remove" button is clicked', () => {
|
||||
const { getByRole } = renderComponent({
|
||||
role: USER_ROLES.staff,
|
||||
});
|
||||
|
||||
const addButton = getByRole('button', { name: messages.addButton.defaultMessage });
|
||||
fireEvent.click(addButton);
|
||||
expect(onChangeRoleMock).toHaveBeenCalledTimes(1);
|
||||
expect(onChangeRoleMock).toHaveBeenCalledWith(emailMock, USER_ROLES.admin);
|
||||
});
|
||||
|
||||
it('calls onDelete when the "Delete" button is clicked', () => {
|
||||
const { getByTestId } = renderComponent();
|
||||
|
||||
const deleteButton = getByTestId('delete-button');
|
||||
fireEvent.click(deleteButton);
|
||||
expect(onDeleteMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('renders the "Hint" when isHideActions is true', () => {
|
||||
const { getByText, queryByRole, queryByTestId } = renderComponent({
|
||||
isHideActions: true,
|
||||
});
|
||||
|
||||
expect(queryByRole('button', { name: messages.addButton.defaultMessage })).not.toBeInTheDocument();
|
||||
expect(queryByTestId('delete-button')).not.toBeInTheDocument();
|
||||
expect(getByText(messages.hint.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
30
src/course-team/course-team-member/messages.js
Normal file
30
src/course-team/course-team-member/messages.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
roleAdmin: {
|
||||
id: 'course-authoring.course-team.member.role.admin',
|
||||
defaultMessage: 'Admin',
|
||||
},
|
||||
roleStaff: {
|
||||
id: 'course-authoring.course-team.member.role.staff',
|
||||
defaultMessage: 'Staff',
|
||||
},
|
||||
roleYou: {
|
||||
id: 'course-authoring.course-team.member.role.you',
|
||||
defaultMessage: 'You!',
|
||||
},
|
||||
hint: {
|
||||
id: 'course-authoring.course-team.member.hint',
|
||||
defaultMessage: 'Promote another member to Admin to remove your admin rights',
|
||||
},
|
||||
addButton: {
|
||||
id: 'course-authoring.course-team.member.button.add',
|
||||
defaultMessage: 'Add admin access',
|
||||
},
|
||||
removeButton: {
|
||||
id: 'course-authoring.course-team.member.button.remove',
|
||||
defaultMessage: 'Remove admin access',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import CourseTeamSidebar from './CourseTeamSidebar';
|
||||
import messages from './messages';
|
||||
import initializeStore from '../../store';
|
||||
|
||||
const courseId = 'course-123';
|
||||
let store;
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<AppProvider store={store} messages={{}}>
|
||||
<IntlProvider locale="en">
|
||||
<CourseTeamSidebar courseId={courseId} {...props} />
|
||||
</IntlProvider>
|
||||
</AppProvider>,
|
||||
);
|
||||
|
||||
describe('<CourseTeamSidebar />', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore();
|
||||
});
|
||||
|
||||
it('render CourseTeamSidebar component correctly', () => {
|
||||
const { getByText } = renderComponent();
|
||||
|
||||
expect(getByText(messages.sidebarTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.sidebarAbout_1.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.sidebarAbout_2.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.sidebarAbout_3.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('render CourseTeamSidebar when isOwnershipHint is true', () => {
|
||||
const { getByText } = renderComponent({ isOwnershipHint: true });
|
||||
|
||||
expect(getByText(messages.ownershipTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(
|
||||
'Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click to make another user the Admin, then ask that user to remove you from the Course Team list.',
|
||||
)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
68
src/course-team/course-team-sidebar/CourseTeamSidebar.jsx
Normal file
68
src/course-team/course-team-sidebar/CourseTeamSidebar.jsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import HelpSidebar from '../../generic/help-sidebar';
|
||||
import messages from './messages';
|
||||
|
||||
const CourseTeamSideBar = ({ courseId, isOwnershipHint, isShowInitialSidebar }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<div
|
||||
className="course-team-sidebar"
|
||||
data-testid={isShowInitialSidebar ? 'course-team-sidebar__initial' : 'course-team-sidebar'}
|
||||
>
|
||||
<HelpSidebar
|
||||
intl={intl}
|
||||
courseId={courseId}
|
||||
showOtherSettings={false}
|
||||
>
|
||||
<h4 className="help-sidebar-about-title">
|
||||
{intl.formatMessage(messages.sidebarTitle)}
|
||||
</h4>
|
||||
<p className="help-sidebar-about-descriptions">
|
||||
{intl.formatMessage(messages.sidebarAbout_1)}
|
||||
</p>
|
||||
<p className="help-sidebar-about-descriptions">
|
||||
{intl.formatMessage(messages.sidebarAbout_2)}
|
||||
</p>
|
||||
<p className="help-sidebar-about-descriptions">
|
||||
{intl.formatMessage(messages.sidebarAbout_3)}
|
||||
</p>
|
||||
</HelpSidebar>
|
||||
{isOwnershipHint && (
|
||||
<>
|
||||
<hr />
|
||||
<HelpSidebar
|
||||
intl={intl}
|
||||
courseId={courseId}
|
||||
showOtherSettings={false}
|
||||
>
|
||||
<h4 className="help-sidebar-about-title">
|
||||
{intl.formatMessage(messages.ownershipTitle)}
|
||||
</h4>
|
||||
<p className="help-sidebar-about-descriptions">
|
||||
{intl.formatMessage(
|
||||
messages.ownershipDescription,
|
||||
{ strong: <strong>{intl.formatMessage(messages.addAdminAccess)}</strong> },
|
||||
)}
|
||||
</p>
|
||||
</HelpSidebar>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
CourseTeamSideBar.defaultProps = {
|
||||
isShowInitialSidebar: false,
|
||||
};
|
||||
|
||||
CourseTeamSideBar.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
isOwnershipHint: PropTypes.bool.isRequired,
|
||||
isShowInitialSidebar: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default CourseTeamSideBar;
|
||||
11
src/course-team/course-team-sidebar/CourseTeamSidebar.scss
Normal file
11
src/course-team/course-team-sidebar/CourseTeamSidebar.scss
Normal file
@@ -0,0 +1,11 @@
|
||||
.course-team-sidebar {
|
||||
.help-sidebar {
|
||||
&:not(:first-child) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/course-team/course-team-sidebar/messages.js
Normal file
34
src/course-team/course-team-sidebar/messages.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
sidebarTitle: {
|
||||
id: 'course-authoring.course-team.sidebar.title',
|
||||
defaultMessage: 'Course team roles',
|
||||
},
|
||||
sidebarAbout_1: {
|
||||
id: 'course-authoring.course-team.sidebar.about-1',
|
||||
defaultMessage: 'Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.',
|
||||
},
|
||||
sidebarAbout_2: {
|
||||
id: 'course-authoring.course-team.sidebar.about-2',
|
||||
defaultMessage: 'Admins are course team members who can add and remove other course team members.',
|
||||
},
|
||||
sidebarAbout_3: {
|
||||
id: 'course-authoring.course-team.sidebar.about-3',
|
||||
defaultMessage: 'All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.',
|
||||
},
|
||||
ownershipTitle: {
|
||||
id: 'course-authoring.course-team.sidebar.ownership.title',
|
||||
defaultMessage: 'Transferring ownership',
|
||||
},
|
||||
ownershipDescription: {
|
||||
id: 'course-authoring.course-team.sidebar.ownership.description',
|
||||
defaultMessage: 'Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.',
|
||||
},
|
||||
addAdminAccess: {
|
||||
id: 'course-authoring.course-team.sidebar.ownership.addAdminAccess',
|
||||
defaultMessage: 'Add admin access',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
54
src/course-team/data/api.js
Normal file
54
src/course-team/data/api.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { USER_ROLES } from '../../constants';
|
||||
|
||||
const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
|
||||
export const getCourseTeamApiUrl = (courseId) => `${getApiBaseUrl()}/api/contentstore/v1/course_team/${courseId}`;
|
||||
export const updateCourseTeamUserApiUrl = (courseId, email) => `${getApiBaseUrl()}/course_team/${courseId}/${email}`;
|
||||
|
||||
/**
|
||||
* Get course team.
|
||||
* @param {string} courseId
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function getCourseTeam(courseId) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.get(getCourseTeamApiUrl(courseId));
|
||||
|
||||
return camelCaseObject(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create course team user.
|
||||
* @param {string} courseId
|
||||
* @param {string} email
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function createTeamUser(courseId, email) {
|
||||
await getAuthenticatedHttpClient()
|
||||
.post(updateCourseTeamUserApiUrl(courseId, email), { role: USER_ROLES.staff });
|
||||
}
|
||||
|
||||
/**
|
||||
* Change role course team user.
|
||||
* @param {string} courseId
|
||||
* @param {string} email
|
||||
* @param {string} role
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function changeRoleTeamUser(courseId, email, role) {
|
||||
await getAuthenticatedHttpClient()
|
||||
.put(updateCourseTeamUserApiUrl(courseId, email), { role });
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete course team user.
|
||||
* @param {string} courseId
|
||||
* @param {string} email
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function deleteTeamUser(courseId, email) {
|
||||
await getAuthenticatedHttpClient()
|
||||
.delete(updateCourseTeamUserApiUrl(courseId, email));
|
||||
}
|
||||
6
src/course-team/data/selectors.js
Normal file
6
src/course-team/data/selectors.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export const getCourseTeamUsers = (state) => state.courseTeam.users;
|
||||
export const getCourseTeamLoadingStatus = (state) => state.courseTeam.loadingCourseTeamStatus;
|
||||
export const getErrorMessage = (state) => state.courseTeam.errorMessage;
|
||||
export const getIsAllowActions = (state) => state.courseTeam.allowActions;
|
||||
export const getIsOwnershipHint = (state) => state.courseTeam.showTransferOwnershipHint;
|
||||
export const getSavingStatus = (state) => state.courseTeam.savingStatus;
|
||||
46
src/course-team/data/slice.js
Normal file
46
src/course-team/data/slice.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'courseTeam',
|
||||
initialState: {
|
||||
loadingCourseTeamStatus: RequestStatus.IN_PROGRESS,
|
||||
savingStatus: '',
|
||||
users: [],
|
||||
showTransferOwnershipHint: false,
|
||||
allowActions: false,
|
||||
errorMessage: '',
|
||||
},
|
||||
reducers: {
|
||||
fetchCourseTeamSuccess: (state, { payload }) => {
|
||||
state.users = payload.users;
|
||||
state.showTransferOwnershipHint = payload.showTransferOwnershipHint;
|
||||
state.allowActions = payload.allowActions;
|
||||
},
|
||||
updateLoadingCourseTeamStatus: (state, { payload }) => {
|
||||
state.loadingCourseTeamStatus = payload.status;
|
||||
},
|
||||
deleteCourseTeamUser: (state, { payload }) => {
|
||||
state.users = state.users.filter((user) => user.email !== payload);
|
||||
},
|
||||
updateSavingStatus: (state, { payload }) => {
|
||||
state.savingStatus = payload.status;
|
||||
},
|
||||
setErrorMessage: (state, { payload }) => {
|
||||
state.errorMessage = payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
fetchCourseTeamSuccess,
|
||||
updateLoadingCourseTeamStatus,
|
||||
deleteCourseTeamUser,
|
||||
updateSavingStatus,
|
||||
setErrorMessage,
|
||||
} = slice.actions;
|
||||
|
||||
export const {
|
||||
reducer,
|
||||
} = slice;
|
||||
87
src/course-team/data/thunk.js
Normal file
87
src/course-team/data/thunk.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
import {
|
||||
getCourseTeam,
|
||||
deleteTeamUser,
|
||||
createTeamUser,
|
||||
changeRoleTeamUser,
|
||||
} from './api';
|
||||
import {
|
||||
fetchCourseTeamSuccess,
|
||||
updateLoadingCourseTeamStatus,
|
||||
deleteCourseTeamUser,
|
||||
updateSavingStatus,
|
||||
setErrorMessage,
|
||||
} from './slice';
|
||||
|
||||
export function fetchCourseTeamQuery(courseId) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateLoadingCourseTeamStatus({ status: RequestStatus.IN_PROGRESS }));
|
||||
|
||||
try {
|
||||
const courseTeam = await getCourseTeam(courseId);
|
||||
dispatch(fetchCourseTeamSuccess(courseTeam));
|
||||
|
||||
dispatch(updateLoadingCourseTeamStatus({ status: RequestStatus.SUCCESSFUL }));
|
||||
return true;
|
||||
} catch (error) {
|
||||
dispatch(updateLoadingCourseTeamStatus({ status: RequestStatus.FAILED }));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createCourseTeamQuery(courseId, email) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.IN_PROGRESS }));
|
||||
|
||||
try {
|
||||
await createTeamUser(courseId, email);
|
||||
const courseTeam = await getCourseTeam(courseId);
|
||||
dispatch(fetchCourseTeamSuccess(courseTeam));
|
||||
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
|
||||
return true;
|
||||
} catch (error) {
|
||||
const message = error?.response?.data?.error || '';
|
||||
dispatch(setErrorMessage(message));
|
||||
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.FAILED }));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function changeRoleTeamUserQuery(courseId, email, role) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.IN_PROGRESS }));
|
||||
|
||||
try {
|
||||
await changeRoleTeamUser(courseId, email, role);
|
||||
const courseTeam = await getCourseTeam(courseId);
|
||||
dispatch(fetchCourseTeamSuccess(courseTeam));
|
||||
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
|
||||
return true;
|
||||
} catch ({ message }) {
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.FAILED }));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteCourseTeamQuery(courseId, email) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.IN_PROGRESS }));
|
||||
|
||||
try {
|
||||
await deleteTeamUser(courseId, email);
|
||||
dispatch(deleteCourseTeamUser(email));
|
||||
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
|
||||
return true;
|
||||
} catch (error) {
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.FAILED }));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
139
src/course-team/hooks.jsx
Normal file
139
src/course-team/hooks.jsx
Normal file
@@ -0,0 +1,139 @@
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useToggle } from '@edx/paragon';
|
||||
|
||||
import { USER_ROLES } from '../constants';
|
||||
import { RequestStatus } from '../data/constants';
|
||||
import { useModel } from '../generic/model-store';
|
||||
import {
|
||||
changeRoleTeamUserQuery,
|
||||
createCourseTeamQuery,
|
||||
deleteCourseTeamQuery,
|
||||
fetchCourseTeamQuery,
|
||||
} from './data/thunk';
|
||||
import {
|
||||
getCourseTeamLoadingStatus,
|
||||
getCourseTeamUsers,
|
||||
getErrorMessage,
|
||||
getIsAllowActions,
|
||||
getIsOwnershipHint, getSavingStatus,
|
||||
} from './data/selectors';
|
||||
import { setErrorMessage } from './data/slice';
|
||||
import { MODAL_TYPES } from './constants';
|
||||
|
||||
const useCourseTeam = ({ courseId }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { email: currentUserEmail } = getAuthenticatedUser();
|
||||
const courseDetails = useModel('courseDetails', courseId);
|
||||
|
||||
const [modalType, setModalType] = useState(MODAL_TYPES.delete);
|
||||
const [isInfoModalOpen, openInfoModal, closeInfoModal] = useToggle(false);
|
||||
const [isFormVisible, openForm, hideForm] = useToggle(false);
|
||||
const [currentEmail, setCurrentEmail] = useState('');
|
||||
const [isQueryPending, setIsQueryPending] = useState(false);
|
||||
const courseTeamUsers = useSelector(getCourseTeamUsers);
|
||||
const errorMessage = useSelector(getErrorMessage);
|
||||
const savingStatus = useSelector(getSavingStatus);
|
||||
const isAllowActions = useSelector(getIsAllowActions);
|
||||
const isOwnershipHint = useSelector(getIsOwnershipHint);
|
||||
const loadingCourseTeamStatus = useSelector(getCourseTeamLoadingStatus);
|
||||
|
||||
const isSingleAdmin = courseTeamUsers.filter((user) => user.role === USER_ROLES.admin).length === 1;
|
||||
|
||||
const handleOpenInfoModal = (type, email) => {
|
||||
setCurrentEmail(email);
|
||||
setModalType(type);
|
||||
openInfoModal();
|
||||
};
|
||||
|
||||
const handleCloseInfoModal = () => {
|
||||
dispatch(setErrorMessage(''));
|
||||
closeInfoModal();
|
||||
};
|
||||
|
||||
const handleAddUserSubmit = (data) => {
|
||||
setIsQueryPending(true);
|
||||
|
||||
const { email } = data;
|
||||
const isUserContains = courseTeamUsers.some((user) => user.email === email);
|
||||
|
||||
if (isUserContains) {
|
||||
handleOpenInfoModal(MODAL_TYPES.warning, email);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(createCourseTeamQuery(courseId, email)).then((result) => {
|
||||
if (result) {
|
||||
hideForm();
|
||||
dispatch(setErrorMessage(''));
|
||||
return;
|
||||
}
|
||||
|
||||
handleOpenInfoModal(MODAL_TYPES.error, email);
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteUserSubmit = () => {
|
||||
setIsQueryPending(true);
|
||||
dispatch(deleteCourseTeamQuery(courseId, currentEmail));
|
||||
handleCloseInfoModal();
|
||||
};
|
||||
|
||||
const handleChangeRoleUserSubmit = (email, role) => {
|
||||
setIsQueryPending(true);
|
||||
dispatch(changeRoleTeamUserQuery(courseId, email, role));
|
||||
};
|
||||
|
||||
const handleInternetConnectionFailed = () => {
|
||||
setIsQueryPending(false);
|
||||
};
|
||||
|
||||
const handleOpenDeleteModal = (email) => {
|
||||
handleOpenInfoModal(MODAL_TYPES.delete, email);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchCourseTeamQuery(courseId));
|
||||
}, [courseId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (savingStatus === RequestStatus.SUCCESSFUL) {
|
||||
setIsQueryPending(false);
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
}, [savingStatus]);
|
||||
|
||||
return {
|
||||
modalType,
|
||||
errorMessage,
|
||||
courseName: courseDetails?.name || '',
|
||||
currentEmail,
|
||||
courseTeamUsers,
|
||||
currentUserEmail,
|
||||
isLoading: loadingCourseTeamStatus === RequestStatus.IN_PROGRESS,
|
||||
isSingleAdmin,
|
||||
isFormVisible,
|
||||
isAllowActions,
|
||||
isInfoModalOpen,
|
||||
isOwnershipHint,
|
||||
isQueryPending,
|
||||
isInternetConnectionAlertFailed: savingStatus === RequestStatus.FAILED,
|
||||
isShowAddTeamMember: courseTeamUsers.length === 1 && isAllowActions,
|
||||
isShowInitialSidebar: !courseTeamUsers.length && !isFormVisible,
|
||||
isShowUserFilledSidebar: Boolean(courseTeamUsers.length) || isFormVisible,
|
||||
openForm,
|
||||
hideForm,
|
||||
closeInfoModal,
|
||||
handleAddUserSubmit,
|
||||
handleOpenInfoModal,
|
||||
handleOpenDeleteModal,
|
||||
handleDeleteUserSubmit,
|
||||
handleChangeRoleUserSubmit,
|
||||
handleInternetConnectionFailed,
|
||||
};
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export { useCourseTeam };
|
||||
75
src/course-team/info-modal/InfoModal.jsx
Normal file
75
src/course-team/info-modal/InfoModal.jsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
ActionRow,
|
||||
Button,
|
||||
AlertModal,
|
||||
} from '@edx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { MODAL_TYPES } from '../constants';
|
||||
import { getInfoModalSettings } from '../utils';
|
||||
|
||||
const InfoModal = ({
|
||||
modalType,
|
||||
isOpen,
|
||||
close,
|
||||
onDeleteSubmit,
|
||||
currentEmail,
|
||||
errorMessage,
|
||||
courseName,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const {
|
||||
title,
|
||||
message,
|
||||
variant,
|
||||
closeButtonText,
|
||||
submitButtonText,
|
||||
closeButtonVariant,
|
||||
} = getInfoModalSettings(modalType, currentEmail, errorMessage, courseName, intl);
|
||||
|
||||
const isEmptyErrorMessage = modalType === MODAL_TYPES.error && !errorMessage;
|
||||
|
||||
return (
|
||||
<AlertModal
|
||||
title={title}
|
||||
variant={variant}
|
||||
isOpen={isOpen && !isEmptyErrorMessage}
|
||||
onClose={close}
|
||||
footerNode={(
|
||||
<ActionRow>
|
||||
<Button variant={closeButtonVariant} onClick={close}>
|
||||
{closeButtonText}
|
||||
</Button>
|
||||
{modalType === MODAL_TYPES.delete && (
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onDeleteSubmit();
|
||||
}}
|
||||
>
|
||||
{submitButtonText}
|
||||
</Button>
|
||||
)}
|
||||
</ActionRow>
|
||||
)}
|
||||
>
|
||||
<p>{message}</p>
|
||||
</AlertModal>
|
||||
);
|
||||
};
|
||||
|
||||
InfoModal.propTypes = {
|
||||
modalType: PropTypes.string.isRequired,
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
close: PropTypes.func.isRequired,
|
||||
currentEmail: PropTypes.string.isRequired,
|
||||
errorMessage: PropTypes.string.isRequired,
|
||||
courseName: PropTypes.string.isRequired,
|
||||
onDeleteSubmit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default InfoModal;
|
||||
85
src/course-team/info-modal/InfoModal.test.jsx
Normal file
85
src/course-team/info-modal/InfoModal.test.jsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import React from 'react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { MODAL_TYPES } from '../constants';
|
||||
import InfoModal from './InfoModal';
|
||||
import messages from './messages';
|
||||
|
||||
const closeMock = jest.fn();
|
||||
const onDeleteSubmitMock = jest.fn();
|
||||
const currentEmailMock = 'user@example.com';
|
||||
const errorMessageMock = 'Error text error@example.com';
|
||||
const courseNameMock = 'Course Name';
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<IntlProvider locale="en">
|
||||
<InfoModal
|
||||
modalType={MODAL_TYPES.delete}
|
||||
isOpen
|
||||
close={closeMock}
|
||||
onDeleteSubmit={onDeleteSubmitMock}
|
||||
currentEmail={currentEmailMock}
|
||||
errorMessage={errorMessageMock}
|
||||
courseName={courseNameMock}
|
||||
{...props}
|
||||
/>
|
||||
</IntlProvider>,
|
||||
);
|
||||
|
||||
describe('<InfoModal />', () => {
|
||||
it('render InfoModal component with type delete correctly', () => {
|
||||
const { getByText, getByRole } = renderComponent({
|
||||
modalType: MODAL_TYPES.delete,
|
||||
});
|
||||
|
||||
expect(getByText(messages.deleteModalTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(
|
||||
messages.deleteModalMessage.defaultMessage
|
||||
.replace('{email}', currentEmailMock)
|
||||
.replace('{courseName}', courseNameMock),
|
||||
)).toBeInTheDocument();
|
||||
expect(getByRole('button', { name: messages.deleteModalCancelButton.defaultMessage })).toBeInTheDocument();
|
||||
expect(getByRole('button', { name: messages.deleteModalDeleteButton.defaultMessage })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('render InfoModal component with type error correctly', () => {
|
||||
const { getByText, getByRole } = renderComponent({
|
||||
modalType: MODAL_TYPES.error,
|
||||
});
|
||||
|
||||
expect(getByText(messages.errorModalTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(errorMessageMock)).toBeInTheDocument();
|
||||
expect(getByRole('button', { name: messages.errorModalOkButton.defaultMessage })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('render InfoModal component with type warning correctly', () => {
|
||||
const { getByText, getByRole } = renderComponent({
|
||||
modalType: MODAL_TYPES.warning,
|
||||
});
|
||||
|
||||
expect(getByText(messages.warningModalTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(
|
||||
messages.warningModalMessage.defaultMessage
|
||||
.replace('{email}', currentEmailMock)
|
||||
.replace('{courseName}', courseNameMock),
|
||||
)).toBeInTheDocument();
|
||||
expect(getByRole('button', { name: messages.warningModalReturnButton.defaultMessage })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls close handler when the close button is clicked', () => {
|
||||
const { getByRole } = renderComponent();
|
||||
|
||||
const closeButton = getByRole('button', { name: messages.deleteModalCancelButton.defaultMessage });
|
||||
fireEvent.click(closeButton);
|
||||
expect(closeMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('calls onDeleteSubmit handler when the delete button is clicked', () => {
|
||||
const { getByRole } = renderComponent();
|
||||
|
||||
const deleteButton = getByRole('button', { name: messages.deleteModalDeleteButton.defaultMessage });
|
||||
fireEvent.click(deleteButton);
|
||||
expect(onDeleteSubmitMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
42
src/course-team/info-modal/messages.js
Normal file
42
src/course-team/info-modal/messages.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteModalTitle: {
|
||||
id: 'course-authoring.course-team.member.button.remove',
|
||||
defaultMessage: 'Are you sure?',
|
||||
},
|
||||
deleteModalMessage: {
|
||||
id: 'course-authoring.course-team.delete-modal.message',
|
||||
defaultMessage: 'Are you sure you want to delete {email} from the course team for “{courseName}”?',
|
||||
},
|
||||
deleteModalDeleteButton: {
|
||||
id: 'course-authoring.course-team.delete-modal.button.delete',
|
||||
defaultMessage: 'Delete',
|
||||
},
|
||||
deleteModalCancelButton: {
|
||||
id: 'course-authoring.course-team.delete-modal.button.cancel',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
errorModalTitle: {
|
||||
id: 'course-authoring.course-team.error-modal.title',
|
||||
defaultMessage: 'Error adding user',
|
||||
},
|
||||
errorModalOkButton: {
|
||||
id: 'course-authoring.course-team.error-modal.button.ok',
|
||||
defaultMessage: 'Ok',
|
||||
},
|
||||
warningModalTitle: {
|
||||
id: 'course-authoring.course-team.warning-modal.title',
|
||||
defaultMessage: 'Already a course team member',
|
||||
},
|
||||
warningModalMessage: {
|
||||
id: 'course-authoring.course-team.warning-modal.message',
|
||||
defaultMessage: '{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.',
|
||||
},
|
||||
warningModalReturnButton: {
|
||||
id: 'course-authoring.course-team.warning-modal.button.return',
|
||||
defaultMessage: 'Return to team listing',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
18
src/course-team/messages.js
Normal file
18
src/course-team/messages.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
headingTitle: {
|
||||
id: 'course-authoring.course-team.headingTitle',
|
||||
defaultMessage: 'Course team',
|
||||
},
|
||||
headingSubtitle: {
|
||||
id: 'course-authoring.course-team.subTitle',
|
||||
defaultMessage: 'Settings',
|
||||
},
|
||||
addNewMemberButton: {
|
||||
id: 'course-authoring.course-team.button.new-team-member',
|
||||
defaultMessage: 'New team member',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
53
src/course-team/utils.js
Normal file
53
src/course-team/utils.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import { MODAL_TYPES } from './constants';
|
||||
import messages from './info-modal/messages';
|
||||
|
||||
/**
|
||||
* Create an info modal settings dependent on modal type
|
||||
* @param {typeof MODAL_TYPES} modalType - one of MODAL_TYPES
|
||||
* @param {string} currentEmail - email in current user
|
||||
* @param {string} errorEmail - email from wrong request
|
||||
* @param {string} courseName - current course name
|
||||
* @returns {{
|
||||
* title: string,
|
||||
* message: string,
|
||||
* variant: string,
|
||||
* closeButtonText: string,
|
||||
* submitButtonText: string,
|
||||
* closeButtonVariant: string
|
||||
* }}
|
||||
*/
|
||||
|
||||
const getInfoModalSettings = (modalType, currentEmail, errorMessage, courseName, intl) => {
|
||||
switch (modalType) {
|
||||
case MODAL_TYPES.delete:
|
||||
return {
|
||||
title: intl.formatMessage(messages.deleteModalTitle),
|
||||
message: intl.formatMessage(messages.deleteModalMessage, { email: currentEmail, courseName }),
|
||||
variant: 'danger',
|
||||
closeButtonText: intl.formatMessage(messages.deleteModalCancelButton),
|
||||
submitButtonText: intl.formatMessage(messages.deleteModalDeleteButton),
|
||||
closeButtonVariant: 'tertiary',
|
||||
};
|
||||
case MODAL_TYPES.error:
|
||||
return {
|
||||
title: intl.formatMessage(messages.errorModalTitle),
|
||||
message: errorMessage,
|
||||
variant: 'danger',
|
||||
closeButtonText: intl.formatMessage(messages.errorModalOkButton),
|
||||
closeButtonVariant: 'danger',
|
||||
};
|
||||
case MODAL_TYPES.warning:
|
||||
return {
|
||||
title: intl.formatMessage(messages.warningModalTitle),
|
||||
message: intl.formatMessage(messages.warningModalMessage, { email: currentEmail, courseName }),
|
||||
variant: 'warning',
|
||||
closeButtonText: intl.formatMessage(messages.warningModalReturnButton),
|
||||
mainButtonVariant: 'primary',
|
||||
};
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export { getInfoModalSettings };
|
||||
@@ -39,7 +39,7 @@ const FormikControl = ({
|
||||
};
|
||||
|
||||
FormikControl.propTypes = {
|
||||
name: PropTypes.element.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
label: PropTypes.element,
|
||||
help: PropTypes.element,
|
||||
className: PropTypes.string,
|
||||
|
||||
@@ -30,7 +30,10 @@ const InternetConnectionAlert = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (isQueryPending) {
|
||||
onQueryProcessing();
|
||||
if (onQueryProcessing) {
|
||||
onQueryProcessing();
|
||||
}
|
||||
|
||||
setShowAlert(!isOnline);
|
||||
|
||||
if (!isOnline) {
|
||||
@@ -63,13 +66,13 @@ const InternetConnectionAlert = ({
|
||||
|
||||
InternetConnectionAlert.defaultProps = {
|
||||
isQueryPending: false,
|
||||
|
||||
onQueryProcessing: null,
|
||||
};
|
||||
|
||||
InternetConnectionAlert.propTypes = {
|
||||
isFailed: PropTypes.bool.isRequired,
|
||||
isQueryPending: PropTypes.bool,
|
||||
onQueryProcessing: PropTypes.func.isRequired,
|
||||
onQueryProcessing: PropTypes.func,
|
||||
onInternetConnectionFailed: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const SubHeader = ({
|
||||
title, subtitle, contentTitle, description, instruction,
|
||||
title, subtitle, contentTitle, description, instruction, headerActions,
|
||||
}) => (
|
||||
<>
|
||||
<header className="sub-header">
|
||||
@@ -10,6 +10,11 @@ const SubHeader = ({
|
||||
<small className="sub-header-title-subtitle">{subtitle}</small>
|
||||
{title}
|
||||
</h2>
|
||||
{headerActions && (
|
||||
<div className="ml-auto sub-header-actions">
|
||||
{headerActions}
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
<header className="sub-header-content">
|
||||
<h2 className="sub-header-content-title">{contentTitle}</h2>
|
||||
@@ -20,12 +25,11 @@ const SubHeader = ({
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
SubHeader.defaultProps = {
|
||||
instruction: '',
|
||||
description: '',
|
||||
headerActions: null,
|
||||
};
|
||||
|
||||
SubHeader.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
subtitle: PropTypes.string.isRequired,
|
||||
@@ -35,6 +39,6 @@ SubHeader.propTypes = {
|
||||
PropTypes.element,
|
||||
PropTypes.string,
|
||||
]),
|
||||
headerActions: PropTypes.node,
|
||||
};
|
||||
|
||||
export default SubHeader;
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
.sub-header {
|
||||
display: flex;
|
||||
|
||||
.sub-header-actions {
|
||||
margin-bottom: 1.75rem;
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-header-title {
|
||||
font: normal $font-weight-bold 2rem/2.25rem $font-family-base;
|
||||
margin-bottom: 1.75rem;
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -606,6 +606,78 @@
|
||||
"course-authoring.schedule-section.license.creative-commons.option.SA.label": "Share alike",
|
||||
"course-authoring.schedule-section.license.creative-commons.option.SA.description": "Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with 'No Derivatives'.",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -640,5 +640,77 @@
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}",
|
||||
"course-authoring.schedule.alert.button.saving": "Saving",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.course-team.headingTitle": "Course team",
|
||||
"course-authoring.course-team.subTitle": "Settings",
|
||||
"course-authoring.course-team.button.new-team-member": "New team member",
|
||||
"course-authoring.course-team.sidebar.title": "Course team roles",
|
||||
"course-authoring.course-team.sidebar.about-1": "Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.",
|
||||
"course-authoring.course-team.sidebar.about-2": "Admins are course team members who can add and remove other course team members.",
|
||||
"course-authoring.course-team.sidebar.about-3": "All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.",
|
||||
"course-authoring.course-team.sidebar.ownership.title": "Transferring ownership",
|
||||
"course-authoring.course-team.sidebar.ownership.description": "Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.",
|
||||
"course-authoring.course-team.sidebar.ownership.addAdminAccess": "Add admin access",
|
||||
"course-authoring.course-team.form.title": "Add a user to your course's team",
|
||||
"course-authoring.course-team.form.label": "User's email address",
|
||||
"course-authoring.course-team.form.placeholder": "example: {email}",
|
||||
"course-authoring.course-team.form.helperText": "Provide the email address of the user you want to add as Staff",
|
||||
"course-authoring.course-team.form.button.addUser": "Add user",
|
||||
"course-authoring.course-team.form.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.add-team-member.title": "Add team members to this course",
|
||||
"course-authoring.course-team.add-team-member.description": "Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.",
|
||||
"course-authoring.course-team.add-team-member.button": "Add a new team member",
|
||||
"course-authoring.course-team.member.role.admin": "Admin",
|
||||
"course-authoring.course-team.member.role.staff": "Staff",
|
||||
"course-authoring.course-team.member.role.you": "You!",
|
||||
"course-authoring.course-team.member.hint": "Promote another member to Admin to remove your admin rights",
|
||||
"course-authoring.course-team.member.button.add": "Add admin access",
|
||||
"course-authoring.course-team.member.button.remove": "Remove admin access",
|
||||
"course-authoring.course-team.delete-modal.title": "Are you sure?",
|
||||
"course-authoring.course-team.delete-modal.message": "Are you sure you want to delete {email} from the course team for “{courseName}”?",
|
||||
"course-authoring.course-team.delete-modal.button.delete": "Delete",
|
||||
"course-authoring.course-team.delete-modal.button.cancel": "Cancel",
|
||||
"course-authoring.course-team.error-modal.title": "Error adding user",
|
||||
"course-authoring.course-team.error-modal.button.ok": "Ok",
|
||||
"course-authoring.course-team.warning-modal.title": "Already a course team member",
|
||||
"course-authoring.course-team.warning-modal.message": "{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.",
|
||||
"course-authoring.course-team.warning-modal.button.return": "Return to team listing",
|
||||
"course-authoring.advanced-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.credit.eligibility.label": "Minimum credit-eligible grade:",
|
||||
"course-authoring.grading-settings.credit.eligibility.description": "% Must be greater than or equal to the course passing grade",
|
||||
"course-authoring.grading-settings.credit.eligibility.error.msg": "Not able to set passing grade to less than:",
|
||||
"course-authoring.grading-settings.deadline.label": "Grace period on deadline:",
|
||||
"course-authoring.grading-settings.deadline.description": "Leeway on due dates",
|
||||
"course-authoring.grading-settings.alert.button.saving": "Saving",
|
||||
"course-authoring.grading-settings.add-new-assignment-type.btn": "New assignment type",
|
||||
"course-authoring.grading-settings.assignment-type.description": "Categories and labels for any exercises that are gradable",
|
||||
"course-authoring.grading-settings.assignment-type.title": "Assignment types",
|
||||
"course-authoring.grading-settings.grading-rules-policies.description": "Deadlines, requirements, and logistics around grading student work",
|
||||
"course-authoring.grading-settings.grading-rules-policies.title": "Grading rules & policies",
|
||||
"course-authoring.grading-settings.credit-eligibility.description": "Settings for course credit eligibility",
|
||||
"course-authoring.grading-settings.credit-eligibility.title": "Credit eligibility",
|
||||
"course-authoring.grading-settings.assignment.type-name.title": "Assignment type name",
|
||||
"course-authoring.grading-settings.assignment.type-name.description": "The general category for this type of assignment, for example, Homework or Midterm Exam. This name is visible to learners.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-1": "The assignment type must have a name.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-3": "There's already another assignment type with this name.",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.title": "Abbreviation",
|
||||
"course-authoring.grading-settings.assignment.abbreviation.description": "This short name for the assignment type (for example, HW or Midterm) appears next to assignments on a learner's Progress page.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.title": "Weight of total grade",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.description": "The weight of all assignments of this type as a percentage of the total grade, for example, 40. Do not include the percent symbol.",
|
||||
"course-authoring.grading-settings.assignment.weight-of-total-grade.error.message": "Please enter an integer between 0 and 100.",
|
||||
"course-authoring.grading-settings.assignment.total-number.title": "Total number",
|
||||
"course-authoring.grading-settings.assignment.total-number.description": "The number of subsections in the course that contain problems of this assignment type.",
|
||||
"course-authoring.grading-settings.assignment.total-number.error.message": "Please enter an integer greater than 0.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.title": "Number of droppable",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.description": "The number of assignments of this type that will be dropped. The lowest scoring assignments are dropped first.",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.error.message": "Please enter non-negative integer.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.description": "There are no assignments of this type in the course.",
|
||||
"course-authoring.grading-settings.assignment.delete.button": "Delete",
|
||||
"course-authoring.grading-settings.assignment.number-of-droppable.second.error.message": "Cannot drop more {type} assignments than are assigned.",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.usage.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.warning.title": "Warning: The number of {type} assignments defined here does not match the current number of {type} assignments in the course:",
|
||||
"course-authoring.grading-settings.assignment.alert.success.title": "The number of {type} assignments in the course matches the number defined here.",
|
||||
"course-authoring.grading-settings.assignment.type-name.error.message-2": "For grading to work, you must change all {initialAssignmentName} subsections to {value}"
|
||||
}
|
||||
|
||||
@@ -14,3 +14,4 @@
|
||||
@import "generic/styles";
|
||||
@import "schedule-and-details/ScheduleAndDetails";
|
||||
@import "pages-and-resources/PagesAndResources";
|
||||
@import "course-team/CourseTeam";
|
||||
|
||||
@@ -10,6 +10,7 @@ import { reducer as gradingSettingsReducer } from './grading-settings/data/slice
|
||||
import { reducer as scheduleAndDetailsReducer } from './schedule-and-details/data/slice';
|
||||
import { reducer as liveReducer } from './pages-and-resources/live/data/slice';
|
||||
import { reducer as filesReducer } from './files-and-uploads/data/slice';
|
||||
import { reducer as courseTeamReducer } from './course-team/data/slice';
|
||||
|
||||
export default function initializeStore(preloadedState = undefined) {
|
||||
return configureStore({
|
||||
@@ -24,6 +25,7 @@ export default function initializeStore(preloadedState = undefined) {
|
||||
gradingSettings: gradingSettingsReducer,
|
||||
models: modelsReducer,
|
||||
live: liveReducer,
|
||||
courseTeam: courseTeamReducer,
|
||||
},
|
||||
preloadedState,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user