chore: fix various lint/type issues found by oxlint (#2850)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// oxlint-disable unicorn/no-thenable
|
||||
import React, { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { camelCase } from 'lodash';
|
||||
|
||||
@@ -28,6 +28,10 @@ const renderComponent = children => (
|
||||
let axiosMock;
|
||||
|
||||
describe('ProctoredExamSettings', () => {
|
||||
/**
|
||||
* @param {boolean} isAdmin
|
||||
* @param {string | undefined} org
|
||||
*/
|
||||
function setupApp(isAdmin = true, org = undefined) {
|
||||
mergeConfig({
|
||||
EXAMS_BASE_URL: 'http://exams.testing.co',
|
||||
|
||||
@@ -107,6 +107,7 @@ const TeamSettings = ({
|
||||
)
|
||||
.when('enabled', {
|
||||
is: true,
|
||||
// oxlint-disable-next-line unicorn/no-thenable
|
||||
then: Yup.array().min(1),
|
||||
})
|
||||
.default([])
|
||||
|
||||
@@ -25,7 +25,7 @@ export function fetchCourseAppSettings(courseId) {
|
||||
sortedDisplayName.push(displayName);
|
||||
});
|
||||
const sortedSettingValues = {};
|
||||
sortedDisplayName.sort().forEach((displayName => {
|
||||
sortedDisplayName.sort((a, b) => a.localeCompare(b)).forEach((displayName => {
|
||||
Object.entries(settingValues).forEach(([key, value]) => {
|
||||
if (value.displayName === displayName) {
|
||||
sortedSettingValues[key] = value;
|
||||
|
||||
@@ -7,7 +7,7 @@ const CertificateSection = ({
|
||||
<section {...rest}>
|
||||
<Stack className="justify-content-between mb-2.5" direction="horizontal">
|
||||
<h2 className="lead section-title mb-0">{title}</h2>
|
||||
{actions && actions}
|
||||
{actions}
|
||||
</Stack>
|
||||
<hr className="mt-0 mb-4" />
|
||||
<div>
|
||||
|
||||
@@ -9,14 +9,14 @@ import {
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { getItemIcon } from '@src/generic/block-type-utils';
|
||||
import { ContainerType } from '@src/generic/key-utils';
|
||||
import { COMPONENT_TYPES } from '@src/generic/block-type-utils/constants';
|
||||
import messages from './messages';
|
||||
import { ContainerState } from './types';
|
||||
import { isRowClickable } from './utils';
|
||||
|
||||
export interface ContainerRowProps {
|
||||
title: string;
|
||||
containerType: ContainerType | keyof typeof COMPONENT_TYPES | string;
|
||||
/** containerType: can be one of `ContainerType` | `COMPONENT_TYPES` or any other string (3rd party XBlocks) */
|
||||
containerType: ContainerType | string;
|
||||
state?: ContainerState;
|
||||
side: 'Before' | 'After';
|
||||
originalName?: string;
|
||||
|
||||
@@ -128,6 +128,7 @@ export function diffPreviewContainerChildren<A extends CourseContainerChildBase,
|
||||
|
||||
// Use new mapB for getting new index for added elements
|
||||
addedA.forEach((addedRow) => {
|
||||
// oxlint-disable-next-line typescript/no-non-null-asserted-optional-chain FIXME: clean this up.
|
||||
updatedA.splice(mapB.get(addedRow.id)?.index!, 0, { ...addedRow, state: 'added' });
|
||||
});
|
||||
|
||||
|
||||
@@ -75,11 +75,17 @@ const TagComponent = ({
|
||||
};
|
||||
|
||||
interface TagsTreeProps {
|
||||
/** Array of taxonomy tags that are applied to the content. */
|
||||
tags: TagTree;
|
||||
/** Key of the parent tag. */
|
||||
parentKey?: string;
|
||||
/** Depth of the parent tag (root), used to render tabs for the tree. */
|
||||
rootDepth?: number;
|
||||
/** Lineage of the tag. */
|
||||
lineage?: string[];
|
||||
/** Function that is called when removing tags from the tree. */
|
||||
removeTagHandler?: (value: string) => void;
|
||||
/** Optional component to render after the tags components. */
|
||||
afterTagsComponent?: React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -121,17 +127,12 @@ interface TagsTreeProps {
|
||||
*
|
||||
*/
|
||||
const TagsTree = ({
|
||||
/** Array of taxonomy tags that are applied to the content. */
|
||||
tags,
|
||||
/** Depth of the parent tag (root), used to render tabs for the tree. */
|
||||
rootDepth = 0,
|
||||
/** Key of the parent tag. */
|
||||
parentKey,
|
||||
/** Lineage of the tag. */
|
||||
lineage = [],
|
||||
/** Function that is called when removing tags from the tree. */
|
||||
removeTagHandler,
|
||||
/** Optional component to render after the tags components. */
|
||||
// oxlint-disable-next-line oxc/only-used-in-recursion
|
||||
afterTagsComponent,
|
||||
}: TagsTreeProps) => {
|
||||
const { isEditMode } = useContext(ContentTagsDrawerContext);
|
||||
|
||||
@@ -10,14 +10,13 @@ export interface CourseStructure {
|
||||
hasChanges: boolean,
|
||||
}
|
||||
|
||||
// TODO: Create interface for all `Object` fields in courseOutline
|
||||
export interface CourseOutline {
|
||||
courseReleaseDate: string;
|
||||
courseStructure: CourseStructure;
|
||||
deprecatedBlocksInfo: Object;
|
||||
deprecatedBlocksInfo: Record<string, any>; // TODO: Create interface for this type
|
||||
discussionsIncontextLearnmoreUrl: string;
|
||||
initialState: Object;
|
||||
initialUserClipboard: Object;
|
||||
initialState: Record<string, any>; // TODO: Create interface for this type
|
||||
initialUserClipboard: Record<string, any>; // TODO: Create interface for this type
|
||||
languageCode: string;
|
||||
lmsLink: string;
|
||||
mfeProctoredExamSettingsUrl: string;
|
||||
|
||||
@@ -70,9 +70,7 @@ const searchResult = {
|
||||
results: [
|
||||
{
|
||||
...mockResult.results[0],
|
||||
hits: [
|
||||
...mockResult.results[0].hits.slice(16, 19),
|
||||
],
|
||||
hits: mockResult.results[0].hits.slice(16, 19),
|
||||
},
|
||||
{
|
||||
...mockResult.results[1],
|
||||
|
||||
@@ -90,6 +90,7 @@ const AddContentButton = ({ name, blockType } : AddContentButtonProps) => {
|
||||
break;
|
||||
default:
|
||||
// istanbul ignore next: unreachable
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
throw new Error(`Unrecognized block type ${blockType}`);
|
||||
}
|
||||
stopCurrentFlow();
|
||||
|
||||
@@ -92,7 +92,7 @@ export const LegacyStatusBar = ({
|
||||
>
|
||||
{courseReleaseDateObj.isValid() ? (
|
||||
<FormattedDate
|
||||
value={courseReleaseDateObj.toString()}
|
||||
value={courseReleaseDateObj.toISOString()}
|
||||
year="numeric"
|
||||
month="short"
|
||||
day="2-digit"
|
||||
|
||||
@@ -110,7 +110,7 @@ const CourseDates = ({
|
||||
<Stack direction="horizontal" gap={2}>
|
||||
<Icon size="sm" className="mb-1" src={Event} />
|
||||
<FormattedDate
|
||||
value={startDate.toString()}
|
||||
value={startDate.toISOString()}
|
||||
year="numeric"
|
||||
month="short"
|
||||
day="2-digit"
|
||||
@@ -119,7 +119,7 @@ const CourseDates = ({
|
||||
<>
|
||||
{' - '}
|
||||
<FormattedDate
|
||||
value={endDate.toString()}
|
||||
value={endDate.toISOString()}
|
||||
year="numeric"
|
||||
month="short"
|
||||
day="2-digit"
|
||||
|
||||
@@ -36,7 +36,7 @@ const ReleaseStatus = ({
|
||||
</span>
|
||||
<Icon className="mr-1" size="sm" src={ClockIcon} />
|
||||
{intl.formatMessage(releaseLabel)}
|
||||
{releaseDate && releaseDate}
|
||||
{releaseDate}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// oxlint-disable unicorn/no-useless-spread
|
||||
/* eslint-disable react/prop-types */
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ const ReleaseInfoComponent = () => {
|
||||
);
|
||||
}
|
||||
|
||||
return releaseInfo.message;
|
||||
// istanbul ignore next
|
||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||
return <>{releaseInfo.message}</>;
|
||||
};
|
||||
|
||||
export default ReleaseInfoComponent;
|
||||
|
||||
@@ -29,6 +29,16 @@ const messages = defineMessages({
|
||||
id: 'course-authoring.course-unit.sidebar.body.note',
|
||||
defaultMessage: 'Note: Do not hide graded assignments after they have been released.',
|
||||
},
|
||||
publishInfoDraftSaved: {
|
||||
id: 'course-authoring.course-unit.publish.info.draft.saved',
|
||||
defaultMessage: 'DRAFT SAVED',
|
||||
description: 'Label for the draft date in the publish info section',
|
||||
},
|
||||
publishLastPublished: {
|
||||
id: 'course-authoring.course-unit.publish.info.last.published',
|
||||
defaultMessage: 'LAST PUBLISHED',
|
||||
description: 'Label for the last published date in the publish info section',
|
||||
},
|
||||
publishInfoPreviouslyPublished: {
|
||||
id: 'course-authoring.course-unit.publish.info.previously-published',
|
||||
defaultMessage: 'Previously published',
|
||||
|
||||
@@ -5,20 +5,32 @@ import {
|
||||
Lock,
|
||||
} from '@openedx/paragon/icons';
|
||||
|
||||
import type { IntlShape } from 'react-intl';
|
||||
|
||||
import { ICON_COLOR_VARIANTS, UNIT_VISIBILITY_STATES } from '../constants';
|
||||
import messages from './messages';
|
||||
|
||||
/**
|
||||
* Get information about the publishing status.
|
||||
* @param {Object} intl - The internationalization object.
|
||||
* @param {boolean} hasChanges - Indicates if there are unpublished changes.
|
||||
* @param {string} editedBy - The user who edited the content.
|
||||
* @param {string} editedOn - The timestamp when the content was edited.
|
||||
* @param {string} publishedBy - The user who last published the content.
|
||||
* @param {string} publishedOn - The timestamp when the content was last published.
|
||||
* @returns {string} Publish information based on the provided parameters.
|
||||
* @param intl - The internationalization object.
|
||||
* @param hasChanges - Indicates if there are unpublished changes.
|
||||
* @param editedBy - The user who edited the content.
|
||||
* @param editedOn - The timestamp when the content was edited.
|
||||
* @param publishedBy - The user who last published the content.
|
||||
* @param publishedOn - The timestamp when the content was last published.
|
||||
* @returns Publish information based on the provided parameters.
|
||||
*/
|
||||
export const getPublishInfo = (intl, hasChanges, editedBy, editedOn, publishedBy, publishedOn) => {
|
||||
// this fn appears to be unused - <SidebarBody> is never called with displayUnitLocation=false.
|
||||
// Ingoring it for coverage for now and we'll delete the whole legacy sidebar soon.
|
||||
// istanbul ignore next
|
||||
export const getPublishInfo = (
|
||||
intl: IntlShape,
|
||||
hasChanges: boolean,
|
||||
editedBy: string,
|
||||
editedOn: string,
|
||||
publishedBy: string,
|
||||
publishedOn: any,
|
||||
): string => {
|
||||
let publishInfoText;
|
||||
if (hasChanges && editedOn && editedBy) {
|
||||
publishInfoText = intl.formatMessage(messages.publishInfoDraftSaved, { editedOn, editedBy });
|
||||
@@ -33,12 +45,12 @@ export const getPublishInfo = (intl, hasChanges, editedBy, editedOn, publishedBy
|
||||
|
||||
/**
|
||||
* Get information about the release status.
|
||||
* @param {Object} intl - The internationalization object.
|
||||
* @param {string} releaseDate - The release date of the content.
|
||||
* @param {string} releaseDateFrom - The section name associated with the release date.
|
||||
* @returns {string|ReactElement} Release information based on the provided parameters.
|
||||
* @param intl - The internationalization object.
|
||||
* @param releaseDate - The release date of the content.
|
||||
* @param releaseDateFrom - The section name associated with the release date.
|
||||
* @returns Release information based on the provided parameters.
|
||||
*/
|
||||
export const getReleaseInfo = (intl, releaseDate, releaseDateFrom) => {
|
||||
export const getReleaseInfo = (intl: IntlShape, releaseDate: string, releaseDateFrom: string) => {
|
||||
if (releaseDate) {
|
||||
return {
|
||||
isScheduled: true,
|
||||
@@ -55,14 +67,14 @@ export const getReleaseInfo = (intl, releaseDate, releaseDateFrom) => {
|
||||
|
||||
/**
|
||||
* Get the icon variant based on the provided visibility state and publication status.
|
||||
* @param {string} visibilityState - The visibility state of the content.
|
||||
* @param {boolean} published - Indicates if the content is published.
|
||||
* @param {boolean} hasChanges - Indicates if there are unpublished changes.
|
||||
* @returns {Object} An object containing the icon component and color variant.
|
||||
* @param visibilityState - The visibility state of the content.
|
||||
* @param published - Indicates if the content is published.
|
||||
* @param hasChanges - Indicates if there are unpublished changes.
|
||||
* @returns An object containing the icon component and color variant.
|
||||
* - iconSrc: The source component for the icon.
|
||||
* - colorVariant: The color variant for the icon.
|
||||
*/
|
||||
export const getIconVariant = (visibilityState, published, hasChanges) => {
|
||||
export const getIconVariant = (visibilityState: string, published: boolean, hasChanges: boolean) => {
|
||||
const iconVariants = {
|
||||
[UNIT_VISIBILITY_STATES.staffOnly]: { iconSrc: Lock, colorVariant: ICON_COLOR_VARIANTS.PRIMARY },
|
||||
[UNIT_VISIBILITY_STATES.live]: { iconSrc: CheckCircleIcon, colorVariant: ICON_COLOR_VARIANTS.GREEN },
|
||||
@@ -81,7 +93,7 @@ export const getIconVariant = (visibilityState, published, hasChanges) => {
|
||||
|
||||
/**
|
||||
* Extracts the clear course unit ID from the given course unit data.
|
||||
* @param {string} id - The course unit ID.
|
||||
* @returns {string} The clear course unit ID extracted from the provided data.
|
||||
* @param id - The course unit ID.
|
||||
* @returns The clear course unit ID extracted from the provided data.
|
||||
*/
|
||||
export const extractCourseUnitId = (id) => id.match(/block@(.+)$/)[1];
|
||||
export const extractCourseUnitId = (id: string): string => id.match(/block@(.+)$/)![1];
|
||||
@@ -27,7 +27,7 @@ const courseId = '1234567890';
|
||||
const closeModalMockFn = jest.fn() as jest.MockedFunction<() => void>;
|
||||
const openModalMockFn = jest.fn() as jest.MockedFunction<() => void>;
|
||||
const scrollToMockFn = jest.fn() as jest.MockedFunction<() => void>;
|
||||
const sections: IXBlock[] | any = camelCaseObject(courseOutlineInfoMock)?.childInfo.children || [];
|
||||
const sections: IXBlock[] = camelCaseObject(courseOutlineInfoMock)?.childInfo.children || [];
|
||||
const subsections: IXBlock[] = sections[1]?.childInfo?.children || [];
|
||||
const units: IXBlock[] = subsections[1]?.childInfo?.children || [];
|
||||
const components: IXBlock[] = units[0]?.childInfo?.children || [];
|
||||
|
||||
@@ -85,7 +85,7 @@ const UnitInfoSettings = () => {
|
||||
|
||||
const handleUpdate = async (
|
||||
isVisible: boolean,
|
||||
groupAccess: Object | null,
|
||||
groupAccess: Record<string, any> | null,
|
||||
isDiscussionEnabled: boolean,
|
||||
) => {
|
||||
// oxlint-disable-next-line @typescript-eslint/await-thenable - this dispatch() IS returning a promise.
|
||||
|
||||
@@ -88,7 +88,7 @@ export const useVideoListProps = ({
|
||||
videos,
|
||||
returnFunction,
|
||||
}) => {
|
||||
const [highlighted, setHighlighted] = React.useState(null);
|
||||
const [highlighted, setHighlighted] = React.useState(/** @type {string | null} */(null));
|
||||
const [
|
||||
showSelectVideoError,
|
||||
setShowSelectVideoError,
|
||||
|
||||
@@ -122,7 +122,7 @@ export interface EditorState {
|
||||
videoSharingEnabledForAll: boolean;
|
||||
videoSharingEnabledForCourse: boolean;
|
||||
videoSharingLearnMoreLink: string;
|
||||
thumbnail: null | any;
|
||||
thumbnail: any;
|
||||
transcripts: any[];
|
||||
selectedVideoTranscriptUrls: Record<string, any>;
|
||||
allowTranscriptDownloads: boolean;
|
||||
@@ -172,7 +172,7 @@ export interface EditorState {
|
||||
additionalAttributes: Record<string, any>;
|
||||
defaultSettings: Record<string, any>;
|
||||
settings: {
|
||||
randomization: null | any; // Not sure what type this field has
|
||||
randomization: any; // Not sure what type this field has
|
||||
scoring: {
|
||||
weight: number;
|
||||
attempts: { unlimited: boolean; number: number | null; };
|
||||
|
||||
@@ -59,8 +59,8 @@ export const networkRequest = ({
|
||||
/**
|
||||
* Tracked fetchByBlockId api method.
|
||||
* Tracked to the `fetchBlock` request key.
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
* @param {func} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {func} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const fetchBlock = ({ ...rest }) => (dispatch, getState) => {
|
||||
dispatch(module.networkRequest({
|
||||
@@ -77,8 +77,8 @@ export const fetchBlock = ({ ...rest }) => (dispatch, getState) => {
|
||||
|
||||
* Tracked fetchStudioView api method.
|
||||
* Tracked to the `fetchBlock` request key.
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
* @param {func} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {func} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const fetchStudioView = ({ ...rest }) => (dispatch, getState) => {
|
||||
dispatch(module.networkRequest({
|
||||
@@ -94,8 +94,8 @@ export const fetchStudioView = ({ ...rest }) => (dispatch, getState) => {
|
||||
/**
|
||||
* Tracked fetchByUnitId api method.
|
||||
* Tracked to the `fetchUnit` request key.
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
* @param {func} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {func} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const fetchUnit = ({ ...rest }) => (dispatch, getState) => {
|
||||
dispatch(module.networkRequest({
|
||||
@@ -111,8 +111,8 @@ export const fetchUnit = ({ ...rest }) => (dispatch, getState) => {
|
||||
/**
|
||||
* Tracked saveBlock api method. Tracked to the `saveBlock` request key.
|
||||
* @param {Object} content
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
* @param {func} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {func} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const saveBlock = ({ content, ...rest }) => (dispatch, getState) => {
|
||||
dispatch(module.networkRequest({
|
||||
@@ -131,8 +131,8 @@ export const saveBlock = ({ content, ...rest }) => (dispatch, getState) => {
|
||||
|
||||
/**
|
||||
* Tracked createBlock api method. Tracked to the `createBlock` request key.
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
* @param {func} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {func} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const createBlock = ({ ...rest }) => (dispatch, getState) => {
|
||||
const blockTitle = selectors.app.blockTitle(getState());
|
||||
|
||||
@@ -78,7 +78,7 @@ describe('CodeEditor', () => {
|
||||
});
|
||||
describe('textArr is undefined', () => {
|
||||
it('returns empty array', () => {
|
||||
let textArr;
|
||||
const textArr = undefined;
|
||||
const diagnostics = hooks.syntaxChecker({ textArr, lang: 'html' });
|
||||
expect(diagnostics).toEqual([]);
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ export const getCourseVideosApiUrl = (courseId) => `${getApiBaseUrl()}/videos/${
|
||||
/**
|
||||
* Fetches the course custom pages for provided course
|
||||
* @param {string} courseId
|
||||
* @returns {Promise<[{}]>}
|
||||
* @returns {Promise<Record<string, any>>}
|
||||
*/
|
||||
export async function getVideos(courseId) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
|
||||
@@ -82,7 +82,7 @@ export const getSortedTranscripts = (languages, transcripts) => {
|
||||
transcriptDisplayNames.push(displayName);
|
||||
});
|
||||
|
||||
const sortedTranscripts = transcriptDisplayNames.sort();
|
||||
const sortedTranscripts = transcriptDisplayNames.sort((a, b) => a.localeCompare(b));
|
||||
const sortedTranscriptCodes = [];
|
||||
sortedTranscripts.forEach(transcript => {
|
||||
Object.entries(languages).forEach(([key, value]) => {
|
||||
|
||||
@@ -12,6 +12,8 @@ interface Props {
|
||||
value: string | number;
|
||||
}
|
||||
|
||||
// Because <Form.Control> is only typed as 'any' in Paragon so far, the props of the following become 'any' :/
|
||||
// oxlint-disable-next-line @typescript-eslint(no-redundant-type-constituents
|
||||
const FormikControl: React.FC<Props & React.ComponentProps<typeof Form.Control>> = ({
|
||||
name,
|
||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||
|
||||
@@ -41,7 +41,7 @@ export async function getCourseRerun(courseId: string): Promise<unknown> {
|
||||
/**
|
||||
* Create or rerun course with data.
|
||||
*/
|
||||
export async function createOrRerunCourse(courseData: Object): Promise<unknown> {
|
||||
export async function createOrRerunCourse(courseData: Record<string, any>): Promise<unknown> {
|
||||
const { data } = await getAuthenticatedHttpClient().post(
|
||||
getCreateOrRerunCourseUrl(),
|
||||
convertObjectToSnakeCase(courseData, true),
|
||||
|
||||
@@ -79,7 +79,7 @@ export function isLibraryV1Key(learningContextKey: string | undefined | null): l
|
||||
}
|
||||
|
||||
/** Check if this is a V1 block key. */
|
||||
export function isBlockV1Key(usageKey: string | undefined | null): usageKey is string {
|
||||
export function isBlockV1Key(usageKey: string | undefined | null): boolean {
|
||||
return typeof usageKey === 'string' && usageKey.startsWith('block-v1:');
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ export const getImportStatusApiUrl = (courseId, fileName) => `${getApiBaseUrl()}
|
||||
/**
|
||||
* Start import course.
|
||||
* @param {string} courseId
|
||||
* @param {Object} fileData
|
||||
* @param {Object} requestConfig
|
||||
* @returns {Promise<Object>}
|
||||
* @param {File} fileData
|
||||
* @param {Record<string, any>} requestConfig
|
||||
* @returns {Promise<Record<string, any>>}
|
||||
*/
|
||||
export async function startCourseImporting(courseId, fileData, requestConfig, updateProgress) {
|
||||
const chunkSize = 20 * 1000000; // 20 MB
|
||||
|
||||
@@ -397,15 +397,16 @@ const AddContent = () => {
|
||||
|
||||
// Include the 'Paste from Clipboard' button if there is an Xblock in the clipboard
|
||||
// that can be pasted
|
||||
const showPasteButton = false
|
||||
const showPasteButton = (
|
||||
// We are not in a unit, subsection, or section, so we can paste any XBlock
|
||||
|| (!(insideUnit || insideSubsection || insideSection) && isPasteable)
|
||||
(!(insideUnit || insideSubsection || insideSection) && isPasteable)
|
||||
// We are in a unit, so we can paste only components
|
||||
|| (insideUnit && showPasteXBlock)
|
||||
// We are in a subsection, so we can only paste units
|
||||
|| (insideSubsection && showPasteUnit)
|
||||
// We are in a section, so we can only paste subsections
|
||||
|| (insideSection && showPasteSubsection);
|
||||
|| (insideSection && showPasteSubsection)
|
||||
);
|
||||
|
||||
if (showPasteButton) {
|
||||
const pasteButton = {
|
||||
|
||||
@@ -28,12 +28,13 @@ interface DisplayNumberComponentProps {
|
||||
count?: string;
|
||||
isPending?: boolean;
|
||||
icon?: React.ComponentType;
|
||||
title?: MessageDescriptor;
|
||||
typeId: 'total' | 'section' | 'subsection' | 'unit' | 'unsupported';
|
||||
title: MessageDescriptor;
|
||||
info?: React.ReactNode;
|
||||
}
|
||||
|
||||
const DisplayNumberComponent = ({
|
||||
count, isPending, icon, title, info,
|
||||
count, isPending, icon, typeId, title, info,
|
||||
}: DisplayNumberComponentProps) => (
|
||||
<>
|
||||
<div className="d-flex align-items-start">
|
||||
@@ -43,7 +44,7 @@ const DisplayNumberComponent = ({
|
||||
<OverlayTrigger
|
||||
placement="top"
|
||||
overlay={(
|
||||
<Tooltip variant="light" id={`${title}-info`}>
|
||||
<Tooltip variant="light" id={`${typeId}-info`}>
|
||||
{info}
|
||||
</Tooltip>
|
||||
)}
|
||||
@@ -100,6 +101,7 @@ export const SummaryCard = ({
|
||||
<DisplayNumberComponent
|
||||
count={totalBlocksStr}
|
||||
isPending={isPending}
|
||||
typeId="total"
|
||||
title={messages.importCourseTotalBlocks}
|
||||
/>
|
||||
</Stack>
|
||||
@@ -107,6 +109,7 @@ export const SummaryCard = ({
|
||||
<DisplayNumberComponent
|
||||
count={sections?.toString()}
|
||||
isPending={isPending}
|
||||
typeId="section"
|
||||
icon={getItemIcon('section')}
|
||||
title={messages.importCourseSections}
|
||||
/>
|
||||
@@ -115,6 +118,7 @@ export const SummaryCard = ({
|
||||
<DisplayNumberComponent
|
||||
count={subsections?.toString()}
|
||||
isPending={isPending}
|
||||
typeId="subsection"
|
||||
icon={getItemIcon('subsection')}
|
||||
title={messages.importCourseSubsections}
|
||||
/>
|
||||
@@ -123,6 +127,7 @@ export const SummaryCard = ({
|
||||
<DisplayNumberComponent
|
||||
count={units?.toString()}
|
||||
isPending={isPending}
|
||||
typeId="unit"
|
||||
icon={getItemIcon('unit')}
|
||||
title={messages.importCourseUnits}
|
||||
/>
|
||||
@@ -132,6 +137,7 @@ export const SummaryCard = ({
|
||||
count={totalComponentsStr}
|
||||
isPending={isPending}
|
||||
icon={Widgets}
|
||||
typeId="unsupported"
|
||||
title={messages.importCourseComponents}
|
||||
info={unsupportedBlocks ? (
|
||||
<FormattedMessage
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface CourseOptimizerState {
|
||||
loadingStatus: string;
|
||||
savingStatus: string;
|
||||
rerunLinkUpdateInProgress: boolean | null;
|
||||
rerunLinkUpdateResult: any | null;
|
||||
rerunLinkUpdateResult: any;
|
||||
}
|
||||
|
||||
export type RootState = {
|
||||
|
||||
@@ -31,7 +31,7 @@ const OpenedXConfigForm = ({
|
||||
const appConfigObj = useModel('appConfigs', selectedAppId);
|
||||
const discussionTopicsModel = useModels('discussionTopics', discussionTopicIds);
|
||||
const legacyAppConfig = {
|
||||
...(appConfigObj || {}),
|
||||
...appConfigObj,
|
||||
divideDiscussionIds,
|
||||
enableInContext: true,
|
||||
enableGradedUnits,
|
||||
@@ -64,6 +64,7 @@ const OpenedXConfigForm = ({
|
||||
.required(intl.formatMessage(messages.restrictedEndDateRequired))
|
||||
.when('startDate', {
|
||||
is: (startDate) => startDate,
|
||||
// oxlint-disable-next-line unicorn/no-thenable
|
||||
then: Yup.string().compare(intl.formatMessage(messages.restrictedEndDateInPast), 'date'),
|
||||
}),
|
||||
startTime: Yup.string().checkFormat(
|
||||
@@ -74,6 +75,7 @@ const OpenedXConfigForm = ({
|
||||
.checkFormat(intl.formatMessage(messages.restrictedEndTimeInValidFormat), 'time')
|
||||
.when('startTime', {
|
||||
is: (startTime) => startTime,
|
||||
// oxlint-disable-next-line unicorn/no-thenable
|
||||
then: Yup.string().compare(intl.formatMessage(messages.restrictedEndTimeInPast), 'time'),
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -4,7 +4,7 @@ import { LICENSE_TYPE, LICENSE_COMMONS_OPTIONS, creativeCommonsVersion } from '.
|
||||
import { generateLicenseURL } from './utils';
|
||||
|
||||
const useLicenseDetails = (license, onChange) => {
|
||||
const [licenseType, setLicenseType] = useState(null);
|
||||
const [licenseType, setLicenseType] = useState(/** @type { string | null } */(null));
|
||||
const [licenseDetails, setLicenseDetails] = useState({});
|
||||
const [licenseURL, setLicenseURL] = useState('');
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export function useIsDesktop() {
|
||||
return useMediaQuery({ query: '(min-width: 992px)' });
|
||||
}
|
||||
|
||||
export function convertObjectToSnakeCase(obj: Object, unpacked = false) {
|
||||
export function convertObjectToSnakeCase(obj: Record<string, any>, unpacked = false) {
|
||||
return Object.keys(obj).reduce((snakeCaseObj, key) => {
|
||||
const snakeCaseKey = snakeCase(key);
|
||||
const value = unpacked ? obj[key] : { value: obj[key] };
|
||||
@@ -45,7 +45,7 @@ export function convertObjectToSnakeCase(obj: Object, unpacked = false) {
|
||||
}, {});
|
||||
}
|
||||
|
||||
export function deepConvertingKeysToCamelCase(obj: any[] | Object | null) {
|
||||
export function deepConvertingKeysToCamelCase(obj: any[] | Record<string, any> | null) {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ export function deepConvertingKeysToCamelCase(obj: any[] | Object | null) {
|
||||
return camelCaseObj;
|
||||
}
|
||||
|
||||
export function deepConvertingKeysToSnakeCase(obj: any[] | Object | null) {
|
||||
export function deepConvertingKeysToSnakeCase(obj: any[] | Record<string, any> | null) {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user