diff --git a/plugins/course-apps/live/Settings.jsx b/plugins/course-apps/live/Settings.jsx index 4a79f5f58..5295d1b42 100644 --- a/plugins/course-apps/live/Settings.jsx +++ b/plugins/course-apps/live/Settings.jsx @@ -1,3 +1,4 @@ +// oxlint-disable unicorn/no-thenable import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { camelCase } from 'lodash'; diff --git a/plugins/course-apps/proctoring/Settings.test.jsx b/plugins/course-apps/proctoring/Settings.test.jsx index 30e837a02..4b10848e8 100644 --- a/plugins/course-apps/proctoring/Settings.test.jsx +++ b/plugins/course-apps/proctoring/Settings.test.jsx @@ -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', diff --git a/plugins/course-apps/teams/Settings.jsx b/plugins/course-apps/teams/Settings.jsx index 1a4a8786d..a81a19a64 100644 --- a/plugins/course-apps/teams/Settings.jsx +++ b/plugins/course-apps/teams/Settings.jsx @@ -107,6 +107,7 @@ const TeamSettings = ({ ) .when('enabled', { is: true, + // oxlint-disable-next-line unicorn/no-thenable then: Yup.array().min(1), }) .default([]) diff --git a/src/advanced-settings/data/thunks.js b/src/advanced-settings/data/thunks.js index d96563360..a6b1f97d1 100644 --- a/src/advanced-settings/data/thunks.js +++ b/src/advanced-settings/data/thunks.js @@ -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; diff --git a/src/certificates/certificate-section/CertificateSection.jsx b/src/certificates/certificate-section/CertificateSection.jsx index 05fab62e8..bf2f638a2 100644 --- a/src/certificates/certificate-section/CertificateSection.jsx +++ b/src/certificates/certificate-section/CertificateSection.jsx @@ -7,7 +7,7 @@ const CertificateSection = ({

{title}

- {actions && actions} + {actions}

diff --git a/src/container-comparison/ContainerRow.tsx b/src/container-comparison/ContainerRow.tsx index ef242ee3e..585ced189 100644 --- a/src/container-comparison/ContainerRow.tsx +++ b/src/container-comparison/ContainerRow.tsx @@ -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; diff --git a/src/container-comparison/utils.ts b/src/container-comparison/utils.ts index 03382418b..e360a35e9 100644 --- a/src/container-comparison/utils.ts +++ b/src/container-comparison/utils.ts @@ -128,6 +128,7 @@ export function diffPreviewContainerChildren { + // 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' }); }); diff --git a/src/content-tags-drawer/TagsTree.tsx b/src/content-tags-drawer/TagsTree.tsx index d17541069..4c66ea253 100644 --- a/src/content-tags-drawer/TagsTree.tsx +++ b/src/content-tags-drawer/TagsTree.tsx @@ -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); diff --git a/src/course-outline/data/types.ts b/src/course-outline/data/types.ts index e3f37a99f..ea0b7496f 100644 --- a/src/course-outline/data/types.ts +++ b/src/course-outline/data/types.ts @@ -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; // TODO: Create interface for this type discussionsIncontextLearnmoreUrl: string; - initialState: Object; - initialUserClipboard: Object; + initialState: Record; // TODO: Create interface for this type + initialUserClipboard: Record; // TODO: Create interface for this type languageCode: string; lmsLink: string; mfeProctoredExamSettingsUrl: string; diff --git a/src/course-outline/outline-sidebar/AddSidebar.test.tsx b/src/course-outline/outline-sidebar/AddSidebar.test.tsx index a8ab575d9..f3dd87a3e 100644 --- a/src/course-outline/outline-sidebar/AddSidebar.test.tsx +++ b/src/course-outline/outline-sidebar/AddSidebar.test.tsx @@ -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], diff --git a/src/course-outline/outline-sidebar/AddSidebar.tsx b/src/course-outline/outline-sidebar/AddSidebar.tsx index 9e3acab5a..6522cabab 100644 --- a/src/course-outline/outline-sidebar/AddSidebar.tsx +++ b/src/course-outline/outline-sidebar/AddSidebar.tsx @@ -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(); diff --git a/src/course-outline/status-bar/LegacyStatusBar.tsx b/src/course-outline/status-bar/LegacyStatusBar.tsx index 72dd347c1..2673dd214 100644 --- a/src/course-outline/status-bar/LegacyStatusBar.tsx +++ b/src/course-outline/status-bar/LegacyStatusBar.tsx @@ -92,7 +92,7 @@ export const LegacyStatusBar = ({ > {courseReleaseDateObj.isValid() ? ( {' - '} {intl.formatMessage(releaseLabel)} - {releaseDate && releaseDate} + {releaseDate}
); diff --git a/src/course-unit/add-component/AddComponent.test.tsx b/src/course-unit/add-component/AddComponent.test.tsx index 9691fbe34..9e5112608 100644 --- a/src/course-unit/add-component/AddComponent.test.tsx +++ b/src/course-unit/add-component/AddComponent.test.tsx @@ -1,3 +1,4 @@ +// oxlint-disable unicorn/no-useless-spread /* eslint-disable react/prop-types */ import userEvent from '@testing-library/user-event'; diff --git a/src/course-unit/legacy-sidebar/components/ReleaseInfoComponent.jsx b/src/course-unit/legacy-sidebar/components/ReleaseInfoComponent.jsx index 9861fa209..e7585c074 100644 --- a/src/course-unit/legacy-sidebar/components/ReleaseInfoComponent.jsx +++ b/src/course-unit/legacy-sidebar/components/ReleaseInfoComponent.jsx @@ -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; diff --git a/src/course-unit/legacy-sidebar/messages.ts b/src/course-unit/legacy-sidebar/messages.ts index 720c113b9..65555fa20 100644 --- a/src/course-unit/legacy-sidebar/messages.ts +++ b/src/course-unit/legacy-sidebar/messages.ts @@ -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', diff --git a/src/course-unit/legacy-sidebar/utils.js b/src/course-unit/legacy-sidebar/utils.ts similarity index 54% rename from src/course-unit/legacy-sidebar/utils.js rename to src/course-unit/legacy-sidebar/utils.ts index 0efbc3e33..a1975ae4a 100644 --- a/src/course-unit/legacy-sidebar/utils.js +++ b/src/course-unit/legacy-sidebar/utils.ts @@ -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 - 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]; diff --git a/src/course-unit/move-modal/moveModal.test.tsx b/src/course-unit/move-modal/moveModal.test.tsx index 4daca485c..de5425f20 100644 --- a/src/course-unit/move-modal/moveModal.test.tsx +++ b/src/course-unit/move-modal/moveModal.test.tsx @@ -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 || []; diff --git a/src/course-unit/unit-sidebar/unit-info/UnitInfoSidebar.tsx b/src/course-unit/unit-sidebar/unit-info/UnitInfoSidebar.tsx index 7adc8d9ee..00a8d6941 100644 --- a/src/course-unit/unit-sidebar/unit-info/UnitInfoSidebar.tsx +++ b/src/course-unit/unit-sidebar/unit-info/UnitInfoSidebar.tsx @@ -85,7 +85,7 @@ const UnitInfoSettings = () => { const handleUpdate = async ( isVisible: boolean, - groupAccess: Object | null, + groupAccess: Record | null, isDiscussionEnabled: boolean, ) => { // oxlint-disable-next-line @typescript-eslint/await-thenable - this dispatch() IS returning a promise. diff --git a/src/editors/containers/VideoGallery/hooks.js b/src/editors/containers/VideoGallery/hooks.js index 7b392463f..a65ee3013 100644 --- a/src/editors/containers/VideoGallery/hooks.js +++ b/src/editors/containers/VideoGallery/hooks.js @@ -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, diff --git a/src/editors/data/redux/index.ts b/src/editors/data/redux/index.ts index 195b63606..ca8b447d2 100644 --- a/src/editors/data/redux/index.ts +++ b/src/editors/data/redux/index.ts @@ -122,7 +122,7 @@ export interface EditorState { videoSharingEnabledForAll: boolean; videoSharingEnabledForCourse: boolean; videoSharingLearnMoreLink: string; - thumbnail: null | any; + thumbnail: any; transcripts: any[]; selectedVideoTranscriptUrls: Record; allowTranscriptDownloads: boolean; @@ -172,7 +172,7 @@ export interface EditorState { additionalAttributes: Record; defaultSettings: Record; 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; }; diff --git a/src/editors/data/redux/thunkActions/requests.js b/src/editors/data/redux/thunkActions/requests.js index b390f124e..a46be3733 100644 --- a/src/editors/data/redux/thunkActions/requests.js +++ b/src/editors/data/redux/thunkActions/requests.js @@ -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()); diff --git a/src/editors/sharedComponents/CodeEditor/index.test.tsx b/src/editors/sharedComponents/CodeEditor/index.test.tsx index ebd667f26..7c9ab7853 100644 --- a/src/editors/sharedComponents/CodeEditor/index.test.tsx +++ b/src/editors/sharedComponents/CodeEditor/index.test.tsx @@ -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([]); }); diff --git a/src/files-and-videos/videos-page/data/api.js b/src/files-and-videos/videos-page/data/api.js index 5135181c5..19d7cd8d4 100644 --- a/src/files-and-videos/videos-page/data/api.js +++ b/src/files-and-videos/videos-page/data/api.js @@ -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>} */ export async function getVideos(courseId) { const { data } = await getAuthenticatedHttpClient() diff --git a/src/files-and-videos/videos-page/data/utils.js b/src/files-and-videos/videos-page/data/utils.js index 371e2af7b..f91f8b1f1 100644 --- a/src/files-and-videos/videos-page/data/utils.js +++ b/src/files-and-videos/videos-page/data/utils.js @@ -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]) => { diff --git a/src/generic/FormikControl.tsx b/src/generic/FormikControl.tsx index e3d56af96..07c4da623 100644 --- a/src/generic/FormikControl.tsx +++ b/src/generic/FormikControl.tsx @@ -12,6 +12,8 @@ interface Props { value: string | number; } +// Because 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> = ({ name, // eslint-disable-next-line react/jsx-no-useless-fragment diff --git a/src/generic/data/api.ts b/src/generic/data/api.ts index ed1745139..8cd9d4668 100644 --- a/src/generic/data/api.ts +++ b/src/generic/data/api.ts @@ -41,7 +41,7 @@ export async function getCourseRerun(courseId: string): Promise { /** * Create or rerun course with data. */ -export async function createOrRerunCourse(courseData: Object): Promise { +export async function createOrRerunCourse(courseData: Record): Promise { const { data } = await getAuthenticatedHttpClient().post( getCreateOrRerunCourseUrl(), convertObjectToSnakeCase(courseData, true), diff --git a/src/generic/key-utils.ts b/src/generic/key-utils.ts index f943e7c82..435766078 100644 --- a/src/generic/key-utils.ts +++ b/src/generic/key-utils.ts @@ -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:'); } diff --git a/src/import-page/data/api.js b/src/import-page/data/api.js index 1955dc98d..9d7bf74e8 100644 --- a/src/import-page/data/api.js +++ b/src/import-page/data/api.js @@ -8,9 +8,9 @@ export const getImportStatusApiUrl = (courseId, fileName) => `${getApiBaseUrl()} /** * Start import course. * @param {string} courseId - * @param {Object} fileData - * @param {Object} requestConfig - * @returns {Promise} + * @param {File} fileData + * @param {Record} requestConfig + * @returns {Promise>} */ export async function startCourseImporting(courseId, fileData, requestConfig, updateProgress) { const chunkSize = 20 * 1000000; // 20 MB diff --git a/src/library-authoring/add-content/AddContent.tsx b/src/library-authoring/add-content/AddContent.tsx index 735ca07e0..73430997a 100644 --- a/src/library-authoring/add-content/AddContent.tsx +++ b/src/library-authoring/add-content/AddContent.tsx @@ -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 = { diff --git a/src/library-authoring/import-course/stepper/SummaryCard.tsx b/src/library-authoring/import-course/stepper/SummaryCard.tsx index 650030660..c7a2ecc50 100644 --- a/src/library-authoring/import-course/stepper/SummaryCard.tsx +++ b/src/library-authoring/import-course/stepper/SummaryCard.tsx @@ -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) => ( <>
@@ -43,7 +44,7 @@ const DisplayNumberComponent = ({ + {info} )} @@ -100,6 +101,7 @@ export const SummaryCard = ({ @@ -107,6 +109,7 @@ export const SummaryCard = ({ @@ -115,6 +118,7 @@ export const SummaryCard = ({ @@ -123,6 +127,7 @@ export const SummaryCard = ({ @@ -132,6 +137,7 @@ export const SummaryCard = ({ count={totalComponentsStr} isPending={isPending} icon={Widgets} + typeId="unsupported" title={messages.importCourseComponents} info={unsupportedBlocks ? ( 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'), }), }), diff --git a/src/schedule-and-details/license-section/hooks.jsx b/src/schedule-and-details/license-section/hooks.jsx index 89a84e091..2c880c736 100644 --- a/src/schedule-and-details/license-section/hooks.jsx +++ b/src/schedule-and-details/license-section/hooks.jsx @@ -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(''); diff --git a/src/utils.tsx b/src/utils.tsx index e81a0e74d..42fc1c456 100644 --- a/src/utils.tsx +++ b/src/utils.tsx @@ -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, 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 | 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 | null) { if (typeof obj !== 'object' || obj === null) { return obj; }