From c6d953fe7b9cc34be1aa61bf3cefb059d4f965f5 Mon Sep 17 00:00:00 2001 From: Ahtisham Shahid Date: Sun, 3 Dec 2023 22:49:08 +0500 Subject: [PATCH 01/18] feat: removed enable_moderation_reason_codes flag (#615) * chore: removed deprecated flag fix: resolved linter error fix: changed workflow fix: changed workflow fix: changed workflow fix: changed workflow fix: changed workflow fix: changed workflow fix: changed workflow fix: changed workflow fix: changed workflow fix: changed workflow fix: changed workflow fix: changed workflow * test: fixed postEditor test case --------- Co-authored-by: Awais Ansari --- src/discussions/common/AlertBanner.jsx | 5 +-- src/discussions/common/AlertBanner.test.jsx | 1 - .../common/EndorsedAlertBanner.test.jsx | 1 - src/discussions/data/hooks.js | 4 +- src/discussions/data/selectors.js | 1 - src/discussions/data/slices.js | 1 - .../post-comments/PostCommentsView.test.jsx | 41 ++++--------------- .../comments/comment/CommentEditor.jsx | 4 +- .../posts/post-editor/PostEditor.jsx | 4 +- .../posts/post-editor/PostEditor.test.jsx | 14 ++++++- src/discussions/posts/post/Post.jsx | 9 ++-- 11 files changed, 31 insertions(+), 54 deletions(-) diff --git a/src/discussions/common/AlertBanner.jsx b/src/discussions/common/AlertBanner.jsx index 474fb701d..e66f7ae92 100644 --- a/src/discussions/common/AlertBanner.jsx +++ b/src/discussions/common/AlertBanner.jsx @@ -10,7 +10,7 @@ import { Report } from '@edx/paragon/icons'; import { AvatarOutlineAndLabelColors } from '../../data/constants'; import { - selectModerationSettings, selectUserHasModerationPrivileges, selectUserIsGroupTa, selectUserIsStaff, + selectUserHasModerationPrivileges, selectUserIsGroupTa, selectUserIsStaff, } from '../data/selectors'; import messages from '../post-comments/messages'; import AlertBar from './AlertBar'; @@ -29,7 +29,6 @@ const AlertBanner = ({ const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges); const userIsGroupTa = useSelector(selectUserIsGroupTa); const userIsGlobalStaff = useSelector(selectUserIsStaff); - const { reasonCodesEnabled } = useSelector(selectModerationSettings); const userIsContentAuthor = getAuthenticatedUser().username === author; const canSeeReportedBanner = abuseFlagged; const canSeeLastEditOrClosedAlert = (userHasModerationPrivileges || userIsGroupTa @@ -45,7 +44,7 @@ const AlertBanner = ({ {intl.formatMessage(messages.abuseFlaggedMessage)} )} - {reasonCodesEnabled && canSeeLastEditOrClosedAlert && ( + { canSeeLastEditOrClosedAlert && ( <> {lastEdit?.reason && ( { const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges); const userIsGroupTa = useSelector(selectUserIsGroupTa); - const { reasonCodesEnabled } = useSelector(selectModerationSettings); const userIsContentAuthor = getAuthenticatedUser().username === author; const canSeeLastEditOrClosedAlert = (userHasModerationPrivileges || userIsContentAuthor || userIsGroupTa); const canSeeReportedBanner = abuseFlagged; return ( - (reasonCodesEnabled && canSeeLastEditOrClosedAlert && (lastEdit?.reason || closed)) || (canSeeReportedBanner) + (canSeeLastEditOrClosedAlert && (lastEdit?.reason || closed)) || (canSeeReportedBanner) ); }; diff --git a/src/discussions/data/selectors.js b/src/discussions/data/selectors.js index b6c9b2e20..0689967e8 100644 --- a/src/discussions/data/selectors.js +++ b/src/discussions/data/selectors.js @@ -33,7 +33,6 @@ export const selectIsPostingEnabled = state => state.config.isPostingEnabled; export const selectModerationSettings = state => ({ postCloseReasons: state.config.postCloseReasons, editReasons: state.config.editReasons, - reasonCodesEnabled: state.config.reasonCodesEnabled, }); export const selectDiscussionProvider = state => state.config.provider; diff --git a/src/discussions/data/slices.js b/src/discussions/data/slices.js index 05f47d3f7..1b8c488ec 100644 --- a/src/discussions/data/slices.js +++ b/src/discussions/data/slices.js @@ -24,7 +24,6 @@ const configSlice = createSlice({ dividedInlineDiscussions: [], dividedCourseWideDiscussions: [], }, - reasonCodesEnabled: false, editReasons: [], postCloseReasons: [], enableInContext: false, diff --git a/src/discussions/post-comments/PostCommentsView.test.jsx b/src/discussions/post-comments/PostCommentsView.test.jsx index 984d3683b..cda492919 100644 --- a/src/discussions/post-comments/PostCommentsView.test.jsx +++ b/src/discussions/post-comments/PostCommentsView.test.jsx @@ -89,11 +89,10 @@ async function getThreadAPIResponse(attr = null) { await executeThunk(fetchThread(discussionPostId), store.dispatch, store.getState); } -async function setupCourseConfig(reasonCodesEnabled = true) { +async function setupCourseConfig() { axiosMock.onGet(`${courseConfigApiUrl}${courseId}/`).reply(200, { has_moderation_privileges: true, isPostingEnabled: true, - reason_codes_enabled: reasonCodesEnabled, editReasons: [ { code: 'reason-1', label: 'reason 1' }, { code: 'reason-2', label: 'reason 2' }, @@ -392,12 +391,12 @@ describe('ThreadView', () => { assertLastUpdateData({ edit_reason_code: 'reason-1' }); }); - it('should close the post directly if reason codes are not enabled', async () => { - await setupCourseConfig(false); - await waitFor(() => renderComponent(discussionPostId)); + it('should reopen the post', async () => { + await setupCourseConfig(); + renderComponent(closedPostId); - const post = await screen.findByTestId('post-thread-1'); - const hoverCard = within(post).getByTestId('hover-card-thread-1'); + const post = screen.getByTestId('post-thread-2'); + const hoverCard = within(post).getByTestId('hover-card-thread-2'); await act(async () => { fireEvent.click( within(hoverCard).getByRole('button', { name: /actions menu/i }), @@ -405,33 +404,11 @@ describe('ThreadView', () => { }); expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); await act(async () => { - fireEvent.click(screen.getByRole('button', { name: /close/i })); + fireEvent.click(screen.getByRole('button', { name: /reopen/i })); }); expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); - assertLastUpdateData({ closed: true }); - }); - - it.each([true, false])( - 'should reopen the post directly when reason codes enabled=%s', - async (reasonCodesEnabled) => { - await setupCourseConfig(reasonCodesEnabled); - renderComponent(closedPostId); - - const post = screen.getByTestId('post-thread-2'); - const hoverCard = within(post).getByTestId('hover-card-thread-2'); - await act(async () => { - fireEvent.click( - within(hoverCard).getByRole('button', { name: /actions menu/i }), - ); - }); - expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); - await act(async () => { - fireEvent.click(screen.getByRole('button', { name: /reopen/i })); - }); - expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); - assertLastUpdateData({ closed: false }); - }, - ); + assertLastUpdateData({ closed: false }); + }); it('should show the editor if the post is edited', async () => { await setupCourseConfig(false); diff --git a/src/discussions/post-comments/comments/comment/CommentEditor.jsx b/src/discussions/post-comments/comments/comment/CommentEditor.jsx index 256be0157..c0a0ed73b 100644 --- a/src/discussions/post-comments/comments/comment/CommentEditor.jsx +++ b/src/discussions/post-comments/comments/comment/CommentEditor.jsx @@ -40,10 +40,10 @@ const CommentEditor = ({ const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges); const userIsGroupTa = useSelector(selectUserIsGroupTa); const userIsStaff = useSelector(selectUserIsStaff); - const { reasonCodesEnabled, editReasons } = useSelector(selectModerationSettings); + const { editReasons } = useSelector(selectModerationSettings); const [submitting, dispatch] = useDispatchWithState(); - const canDisplayEditReason = (reasonCodesEnabled && edit + const canDisplayEditReason = (edit && (userHasModerationPrivileges || userIsGroupTa || userIsStaff) && author !== authenticatedUser.username ); diff --git a/src/discussions/posts/post-editor/PostEditor.jsx b/src/discussions/posts/post-editor/PostEditor.jsx index 5231dac2e..8a15ca8aa 100644 --- a/src/discussions/posts/post-editor/PostEditor.jsx +++ b/src/discussions/posts/post-editor/PostEditor.jsx @@ -75,12 +75,12 @@ const PostEditor = ({ const userIsGroupTa = useSelector(selectUserIsGroupTa); const settings = useSelector(selectDivisionSettings); const { allowAnonymous, allowAnonymousToPeers } = useSelector(selectAnonymousPostingConfig); - const { reasonCodesEnabled, editReasons } = useSelector(selectModerationSettings); + const { editReasons } = useSelector(selectModerationSettings); const userIsStaff = useSelector(selectUserIsStaff); const archivedTopics = useSelector(selectArchivedTopics); const postEditorId = `post-editor-${editExisting ? postId : 'new'}`; - const canDisplayEditReason = (reasonCodesEnabled && editExisting + const canDisplayEditReason = (editExisting && (userHasModerationPrivileges || userIsGroupTa || userIsStaff) && post?.author !== authenticatedUser.username ); diff --git a/src/discussions/posts/post-editor/PostEditor.test.jsx b/src/discussions/posts/post-editor/PostEditor.test.jsx index 1c8bda181..49a15693d 100644 --- a/src/discussions/posts/post-editor/PostEditor.test.jsx +++ b/src/discussions/posts/post-editor/PostEditor.test.jsx @@ -266,7 +266,18 @@ describe('PostEditor', () => { test('cancel posting of existing post', async () => { const threadId = 'thread-1'; - await setupData(); + await setupData({ + editReasons: [ + { + code: 'reason-1', + label: 'Reason 1', + }, + { + code: 'reason-2', + label: 'Reason 2', + }, + ], + }); await act(async () => { axiosMock.onGet(`${threadsApiUrl}${threadId}/`).reply(200, Factory.build('thread')); await executeThunk(fetchThread(threadId), store.dispatch, store.getState); @@ -292,7 +303,6 @@ describe('PostEditor', () => { config: { provider: 'legacy', hasModerationPrivileges: true, - reasonCodesEnabled: true, editReasons: [ { code: 'reason-1', diff --git a/src/discussions/posts/post/Post.jsx b/src/discussions/posts/post/Post.jsx index 1f7ee1f92..7ec90218b 100644 --- a/src/discussions/posts/post/Post.jsx +++ b/src/discussions/posts/post/Post.jsx @@ -17,7 +17,7 @@ import { AlertBanner, Confirmation } from '../../common'; import { DiscussionContext } from '../../common/context'; import HoverCard from '../../common/HoverCard'; import { ContentTypes } from '../../data/constants'; -import { selectModerationSettings, selectUserHasModerationPrivileges } from '../../data/selectors'; +import { selectUserHasModerationPrivileges } from '../../data/selectors'; import { selectTopic } from '../../topics/data/selectors'; import { selectThread } from '../data/selectors'; import { removeThread, updateExistingThread } from '../data/thunks'; @@ -41,7 +41,6 @@ const Post = ({ handleAddResponseButton }) => { const topic = useSelector(selectTopic(topicId)); const getTopicSubsection = useSelector(selectorForUnitSubsection); const topicContext = useSelector(selectTopicContext(topicId)); - const { reasonCodesEnabled } = useSelector(selectModerationSettings); const [isDeleting, showDeleteConfirmation, hideDeleteConfirmation] = useToggle(false); const [isReporting, showReportConfirmation, hideReportConfirmation] = useToggle(false); const [isClosing, showClosePostModal, hideClosePostModal] = useToggle(false); @@ -70,12 +69,10 @@ const Post = ({ handleAddResponseButton }) => { const handlePostClose = useCallback(() => { if (closed) { dispatch(updateExistingThread(postId, { closed: false })); - } else if (reasonCodesEnabled) { - showClosePostModal(); } else { - dispatch(updateExistingThread(postId, { closed: true })); + showClosePostModal(); } - }, [closed, postId, reasonCodesEnabled, showClosePostModal]); + }, [closed, postId, showClosePostModal]); const handlePostCopyLink = useCallback(() => { const postURL = new URL(`${getConfig().PUBLIC_PATH}${courseId}/posts/${postId}`, window.location.origin); From 68505821bbc9c119dac6c43a59e83489557fc139 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 11:51:58 +0500 Subject: [PATCH 02/18] fix(deps): update dependency @edx/paragon to v20.46.3 (#611) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 30 +++++++++++++++++------------- package.json | 2 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 09b5f07f9..e1dc0c9a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@edx/frontend-component-footer": "12.5.1", "@edx/frontend-component-header": "4.9.1", "@edx/frontend-platform": "4.6.3", - "@edx/paragon": "20.44.0", + "@edx/paragon": "20.46.3", "@reduxjs/toolkit": "1.8.0", "@tinymce/tinymce-react": "3.13.1", "babel-polyfill": "6.26.0", @@ -3618,9 +3618,9 @@ } }, "node_modules/@edx/paragon": { - "version": "20.44.0", - "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.44.0.tgz", - "integrity": "sha512-C1uC3RaRmlFANtHebFdZzVDM08vgFJRnHE3u97ix07e0ACSQDbVNoZ2H7JgBy8nqHz2JWGHPnvtpvPf5DAZsZQ==", + "version": "20.46.3", + "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.46.3.tgz", + "integrity": "sha512-cHxoxoOREVFbBqW9IRAtlIAQo1lcF9JJXkLoEw1Vam6oetKSa5Mc0SL5kykbV+1iRPP7kS8A0Csf5nRr0oolLQ==", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/react-fontawesome": "^0.1.18", @@ -3663,9 +3663,9 @@ } }, "node_modules/@edx/paragon/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3681,9 +3681,9 @@ } }, "node_modules/@edx/paragon/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -3692,9 +3692,13 @@ } }, "node_modules/@edx/paragon/node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } diff --git a/package.json b/package.json index e17135648..9a5310cdf 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@edx/frontend-component-footer": "12.5.1", "@edx/frontend-component-header": "4.9.1", "@edx/frontend-platform": "4.6.3", - "@edx/paragon": "20.44.0", + "@edx/paragon": "20.46.3", "@reduxjs/toolkit": "1.8.0", "@tinymce/tinymce-react": "3.13.1", "babel-polyfill": "6.26.0", From 5cc8ba43fe1b1e8d808a994d64901875a1b959aa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:51:30 +0500 Subject: [PATCH 03/18] fix(deps): update dependency @edx/frontend-component-header to v4.10.1 (#610) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e1dc0c9a0..2484635ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", "@edx/frontend-component-footer": "12.5.1", - "@edx/frontend-component-header": "4.9.1", + "@edx/frontend-component-header": "4.10.1", "@edx/frontend-platform": "4.6.3", "@edx/paragon": "20.46.3", "@reduxjs/toolkit": "1.8.0", @@ -3326,9 +3326,9 @@ } }, "node_modules/@edx/frontend-component-header": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-4.9.1.tgz", - "integrity": "sha512-OcCWkdRNihZhT5WkZcKRjHCeD883TACIUi27921g5LG2/7+++9EUG74JGtVDYklk0JCuhr0M9tD87YM4BySlaA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-4.10.1.tgz", + "integrity": "sha512-bcQ+ebdy/lM2TfLVB+WhdWNsuc51cFVgt5UQuJcV5nw6ACYUkBVTLbGDT7J8797bsQe6Lywg7Cj9ykB+Dy78Kw==", "dependencies": { "@edx/paragon": "21.5.6", "@fortawesome/fontawesome-svg-core": "6.4.2", diff --git a/package.json b/package.json index 9a5310cdf..282f73a6f 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "dependencies": { "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", "@edx/frontend-component-footer": "12.5.1", - "@edx/frontend-component-header": "4.9.1", + "@edx/frontend-component-header": "4.10.1", "@edx/frontend-platform": "4.6.3", "@edx/paragon": "20.46.3", "@reduxjs/toolkit": "1.8.0", From c4f7115732a00a073522955ea9d7bad4c0f517f2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 13:01:08 +0500 Subject: [PATCH 04/18] fix(deps): update dependency @edx/frontend-component-footer to v12.6.0 (#609) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2484635ec..8e0ab70f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "AGPL-3.0", "dependencies": { "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", - "@edx/frontend-component-footer": "12.5.1", + "@edx/frontend-component-footer": "12.6.0", "@edx/frontend-component-header": "4.10.1", "@edx/frontend-platform": "4.6.3", "@edx/paragon": "20.46.3", @@ -3126,9 +3126,9 @@ } }, "node_modules/@edx/frontend-component-footer": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.5.1.tgz", - "integrity": "sha512-bLXfSDyyf8z+n4VXkraQ98qhkc+ZXuvRy65kXUE3s560oDv0qdiKU054W8uPY6wtsdu4WQ50C/Mluxzd60UKUg==", + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.6.0.tgz", + "integrity": "sha512-s+YwcThkETBcyRji2Zl7CTYebrsqevP0rmTYyycEL952HkpbQ7EY8Ym0wYH2sp/ZnZ9bTyEeWsiQS5l7eMyY1A==", "dependencies": { "@edx/paragon": "^21.3.1", "@fortawesome/fontawesome-svg-core": "6.4.2", diff --git a/package.json b/package.json index 282f73a6f..c4eb87b4c 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "dependencies": { "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", - "@edx/frontend-component-footer": "12.5.1", + "@edx/frontend-component-footer": "12.6.0", "@edx/frontend-component-header": "4.10.1", "@edx/frontend-platform": "4.6.3", "@edx/paragon": "20.46.3", From ac635edcb868ae67c5ac3dfc9161731ad56cc07c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 13:07:44 +0500 Subject: [PATCH 05/18] chore(deps): update dependency @edx/frontend-build to v13.0.8 (#608) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 34 +++++++++++++++++----------------- package.json | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e0ab70f0..0d3c8e9e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@edx/browserslist-config": "1.2.0", - "@edx/frontend-build": "13.0.5", + "@edx/frontend-build": "13.0.8", "@edx/reactifex": "1.1.0", "@testing-library/jest-dom": "5.17.0", "@testing-library/react": "12.1.5", @@ -2057,9 +2057,9 @@ } }, "node_modules/@edx/frontend-build": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@edx/frontend-build/-/frontend-build-13.0.5.tgz", - "integrity": "sha512-cGCw4deCTjLTt2kVoMKOOo+8HS+CSpRjlZBEln1Qfu/868PEB0IWM1E3c7d0rIlkR9kkt7s7WFpYxcs1fk7Ryw==", + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@edx/frontend-build/-/frontend-build-13.0.8.tgz", + "integrity": "sha512-TXUoF7BTIHe4h+W4Dt9+Gf8PXnfVJRwLKitEkpYUH5r4kDEJfyKKGYSbizkciGI+9QScbhm2u8Alv2agDXV1TA==", "dependencies": { "@babel/cli": "7.22.5", "@babel/core": "7.22.5", @@ -2103,11 +2103,11 @@ "postcss": "8.4.31", "postcss-custom-media": "10.0.2", "postcss-loader": "7.3.3", - "postcss-rtlcss": "4.0.8", + "postcss-rtlcss": "4.0.9", "react-dev-utils": "12.0.1", "react-refresh": "0.14.0", "resolve-url-loader": "5.0.0", - "sass": "1.65.1", + "sass": "1.69.5", "sass-loader": "13.3.2", "sharp": "0.32.6", "source-map-loader": "4.0.1", @@ -19823,14 +19823,14 @@ } }, "node_modules/postcss-rtlcss": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/postcss-rtlcss/-/postcss-rtlcss-4.0.8.tgz", - "integrity": "sha512-CR2sY889PHnX6K8rjW9FG4Qvm9UJsIekDakMtEYGH3zgFp9XADMeaKcA0hPOmkClNh0jWbkaPBm0jZ6fHmqkJQ==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-rtlcss/-/postcss-rtlcss-4.0.9.tgz", + "integrity": "sha512-dCNKEf+FgTv+EA3XI8ysg2RnpS5s3/iZmU+9qpCNFxHU/BhK+4hz7jyCsCAfo0CLnDrMPtaQENhwb+EGm1wh7Q==", "dependencies": { - "rtlcss": "4.1.0" + "rtlcss": "4.1.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "postcss": "^8.4.21" @@ -21364,9 +21364,9 @@ } }, "node_modules/rtlcss": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.0.tgz", - "integrity": "sha512-W+N4hh0nVqVrrn3mRkHakxpB+c9cQ4CRT67O39kgA+1DjyhrdsqyCqIuHXyvWaXn4/835n+oX3fYJCi4+G/06A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.1.tgz", + "integrity": "sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0", @@ -21624,9 +21624,9 @@ } }, "node_modules/sass": { - "version": "1.65.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.65.1.tgz", - "integrity": "sha512-9DINwtHmA41SEd36eVPQ9BJKpn7eKDQmUHmpI0y5Zv2Rcorrh0zS+cFrt050hdNbmmCNKTW3hV5mWfuegNRsEA==", + "version": "1.69.5", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.5.tgz", + "integrity": "sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", diff --git a/package.json b/package.json index c4eb87b4c..8db2f492a 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ }, "devDependencies": { "@edx/browserslist-config": "1.2.0", - "@edx/frontend-build": "13.0.5", + "@edx/frontend-build": "13.0.8", "@edx/reactifex": "1.1.0", "@testing-library/jest-dom": "5.17.0", "@testing-library/react": "12.1.5", From df4a3c2a739c26eae2d1f453a51097bae17bb60e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 16:15:31 +0500 Subject: [PATCH 06/18] chore(deps): update dependency rosie to v2.1.1 (#605) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0d3c8e9e8..6b73864e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "glob": "7.2.0", "husky": "7.0.4", "jest": "27.5.1", - "rosie": "2.1.0" + "rosie": "2.1.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -21347,9 +21347,9 @@ } }, "node_modules/rosie": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/rosie/-/rosie-2.1.0.tgz", - "integrity": "sha512-Dbzdc+prLXZuB/suRptDnBUY29SdGvND3bLg6cll8n7PNqzuyCxSlRfrkn8PqjS9n4QVsiM7RCvxCkKAkTQRjA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/rosie/-/rosie-2.1.1.tgz", + "integrity": "sha512-2AXB7WrIZXtKMZ6Q/PlozqPF5nu/x7NEvRJZOblrJuprrPfm5gL8JVvJPj9aaib9F8IUALnLUFhzXrwEtnI5cQ==", "dev": true, "engines": { "node": ">=10" diff --git a/package.json b/package.json index 8db2f492a..f110fec1e 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,6 @@ "glob": "7.2.0", "husky": "7.0.4", "jest": "27.5.1", - "rosie": "2.1.0" + "rosie": "2.1.1" } } From c61435546dc02323c3a878fc3601fa68d86ac226 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:03:29 +0500 Subject: [PATCH 07/18] fix(deps): update dependency regenerator-runtime to v0.14.0 (#622) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6b73864e2..43b6b79b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "react-router": "5.2.1", "react-router-dom": "5.3.0", "redux": "4.1.2", - "regenerator-runtime": "0.13.9", + "regenerator-runtime": "0.14.0", "timeago.js": "4.0.2", "tinymce": "5.10.7", "yup": "0.31.1" @@ -21068,9 +21068,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/regenerator-transform": { "version": "0.15.2", diff --git a/package.json b/package.json index f110fec1e..fda4d0278 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "react-router": "5.2.1", "react-router-dom": "5.3.0", "redux": "4.1.2", - "regenerator-runtime": "0.13.9", + "regenerator-runtime": "0.14.0", "timeago.js": "4.0.2", "tinymce": "5.10.7", "yup": "0.31.1" From 0d5df18ab2a1e7917d188c38b9e72abaf46a2553 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:21:46 +0500 Subject: [PATCH 08/18] fix(deps): update dependency redux to v4.2.1 (#621) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 43b6b79b0..a423120e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "react-redux": "7.2.9", "react-router": "5.2.1", "react-router-dom": "5.3.0", - "redux": "4.1.2", + "redux": "4.2.1", "regenerator-runtime": "0.14.0", "timeago.js": "4.0.2", "tinymce": "5.10.7", @@ -21036,9 +21036,9 @@ } }, "node_modules/redux": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", - "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", "dependencies": { "@babel/runtime": "^7.9.2" } diff --git a/package.json b/package.json index fda4d0278..73044d636 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "react-redux": "7.2.9", "react-router": "5.2.1", "react-router-dom": "5.3.0", - "redux": "4.1.2", + "redux": "4.2.1", "regenerator-runtime": "0.14.0", "timeago.js": "4.0.2", "tinymce": "5.10.7", From b36c0266fdcb21f85b6b5ec8c8dbac93a8f22cde Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Wed, 6 Dec 2023 17:50:28 +0530 Subject: [PATCH 09/18] fix: null error at useRouteMatch when running on tutor (#613) tutor sets the PUBLIC_PATH to '/discussions' which causes frontend-platform to treat all URLs for matching etc to be relative to this path. Since many places include '/discussions' in the match it causes those matches to break. This change makes the default PUBLIC_PATH in .env.development to match the one set by tutor and removes it from the base path of the router letting frontend platform handle the prefix. This also allows for deployments to customise this path to be something other than 'discussions'. --- src/data/constants.js | 5 ++++- .../post-comments/PostCommentsView.test.jsx | 14 ++++++++++++++ .../posts/data/__factories__/threads.factory.js | 1 + src/discussions/posts/post/Post.jsx | 7 +++---- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/data/constants.js b/src/data/constants.js index d0c7960cb..dc786b439 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -1,6 +1,9 @@ import { getConfig } from '@edx/frontend-platform'; export const getApiBaseUrl = () => getConfig().LMS_BASE_URL; +export const getFullUrl = (path) => ( + new URL(`${getConfig().PUBLIC_PATH.replace(/\/$/, '')}/${path}`, window.location.origin).href +); /** * Enum for thread types. @@ -137,7 +140,7 @@ export const DiscussionProvider = { OPEN_EDX: 'openedx', }; -const BASE_PATH = `${getConfig().PUBLIC_PATH}:courseId`; +const BASE_PATH = '/:courseId'; export const Routes = { DISCUSSIONS: { diff --git a/src/discussions/post-comments/PostCommentsView.test.jsx b/src/discussions/post-comments/PostCommentsView.test.jsx index cda492919..07540f4ae 100644 --- a/src/discussions/post-comments/PostCommentsView.test.jsx +++ b/src/discussions/post-comments/PostCommentsView.test.jsx @@ -442,6 +442,20 @@ describe('ThreadView', () => { assertLastUpdateData({ pinned: false }); }); + it('should allow copying a link to the post', async () => { + await waitFor(() => renderComponent(discussionPostId)); + const post = await screen.findByTestId('post-thread-1'); + const hoverCard = within(post).getByTestId('hover-card-thread-1'); + Object.assign(navigator, { clipboard: { writeText: jest.fn() } }); + await act(async () => { + fireEvent.click(within(hoverCard).getByRole('button', { name: /actions menu/i })); + }); + await act(async () => { + fireEvent.click(within(hoverCard).getByRole('button', { name: /copy link/i })); + }); + expect(navigator.clipboard.writeText).toHaveBeenCalledWith(`http://localhost/${courseId}/posts/${discussionPostId}`); + }); + it('should allow reporting the post', async () => { await waitFor(() => renderComponent(discussionPostId)); const post = await screen.findByTestId('post-thread-1'); diff --git a/src/discussions/posts/data/__factories__/threads.factory.js b/src/discussions/posts/data/__factories__/threads.factory.js index fbd9aab30..b072860c8 100644 --- a/src/discussions/posts/data/__factories__/threads.factory.js +++ b/src/discussions/posts/data/__factories__/threads.factory.js @@ -26,6 +26,7 @@ Factory.define('thread') 'type', 'voted', 'pinned', + 'copy_link', ], author: 'test_user', author_label: 'Staff', diff --git a/src/discussions/posts/post/Post.jsx b/src/discussions/posts/post/Post.jsx index 7ec90218b..721397bbf 100644 --- a/src/discussions/posts/post/Post.jsx +++ b/src/discussions/posts/post/Post.jsx @@ -11,7 +11,7 @@ import { useIntl } from '@edx/frontend-platform/i18n'; import { Hyperlink, useToggle } from '@edx/paragon'; import HTMLLoader from '../../../components/HTMLLoader'; -import { ContentActions } from '../../../data/constants'; +import { ContentActions, getFullUrl } from '../../../data/constants'; import { selectorForUnitSubsection, selectTopicContext } from '../../../data/selectors'; import { AlertBanner, Confirmation } from '../../common'; import { DiscussionContext } from '../../common/context'; @@ -37,7 +37,7 @@ const Post = ({ handleAddResponseButton }) => { const location = useLocation(); const history = useHistory(); const dispatch = useDispatch(); - const courseId = useSelector((state) => state.config.id); + const { courseId } = useContext(DiscussionContext); const topic = useSelector(selectTopic(topicId)); const getTopicSubsection = useSelector(selectorForUnitSubsection); const topicContext = useSelector(selectTopicContext(topicId)); @@ -75,8 +75,7 @@ const Post = ({ handleAddResponseButton }) => { }, [closed, postId, showClosePostModal]); const handlePostCopyLink = useCallback(() => { - const postURL = new URL(`${getConfig().PUBLIC_PATH}${courseId}/posts/${postId}`, window.location.origin); - navigator.clipboard.writeText(postURL.href); + navigator.clipboard.writeText(getFullUrl(`${courseId}/posts/${postId}`)); }, [window.location.origin, postId, courseId]); const handlePostPin = useCallback(() => dispatch( From b35632df641bd6b1d7f07b71f1a1696918e6f277 Mon Sep 17 00:00:00 2001 From: Syed Ali Abbas Zaidi <88369802+Syed-Ali-Abbas-Zaidi@users.noreply.github.com> Date: Thu, 7 Dec 2023 18:10:48 +0500 Subject: [PATCH 10/18] feat: upgrade react router to v6 (#542) * feat: upgrade react router to v6 * fix: routing issues * fix: category route should redirect to all posts * fix: path error on routes --- package-lock.json | 94 ++++++++----------- package.json | 6 +- src/components/TinyMCEEditor.jsx | 2 +- src/data/constants.js | 41 ++++---- src/discussions/common/AuthorLabel.jsx | 3 +- src/discussions/common/HoverCard.test.jsx | 9 +- src/discussions/data/hooks.js | 20 ++-- .../discussions-home/DiscussionContent.jsx | 32 +++---- .../discussions-home/DiscussionSidebar.jsx | 82 +++++++++------- .../DiscussionSidebar.test.jsx | 6 +- .../discussions-home/DiscussionsHome.jsx | 74 ++++++++++----- .../discussions-home/DiscussionsHome.test.jsx | 4 +- .../empty-posts/EmptyPosts.test.jsx | 2 +- src/discussions/empty-posts/EmptyTopics.jsx | 9 +- .../empty-posts/EmptyTopics.test.jsx | 11 ++- .../in-context-topics/TopicPostsView.test.jsx | 59 ++++++++---- .../in-context-topics/TopicsView.test.jsx | 27 +++--- .../components/BackButton.jsx | 6 +- .../components/EmptyTopics.jsx | 11 +-- .../topic/SectionBaseGroup.jsx | 5 +- .../in-context-topics/topic/Topic.jsx | 5 +- src/discussions/learners/LearnerPostsView.jsx | 6 +- .../learners/LearnerPostsView.test.jsx | 24 ++--- src/discussions/learners/LearnersView.jsx | 15 +-- .../learners/LearnersView.test.jsx | 19 ++-- .../LearnerPostFilterBar.test.jsx | 41 +++----- .../learners/learner/LearnerCard.jsx | 2 +- .../breadcrumb-menu/BreadcrumbDropdown.jsx | 4 +- .../breadcrumb-menu/LegacyBreadcrumbMenu.jsx | 12 +-- .../LegacyBreadcrumbMenu.test.jsx | 27 ++++-- .../navigation-bar/NavigationBar.jsx | 10 +- .../post-comments/PostCommentsView.jsx | 19 ++-- .../post-comments/PostCommentsView.test.jsx | 54 ++++++++--- src/discussions/posts/NoResults.test.jsx | 2 +- src/discussions/posts/PostsView.test.jsx | 43 +++++---- .../posts/post-editor/PostEditor.jsx | 6 +- .../posts/post-editor/PostEditor.test.jsx | 16 ++-- src/discussions/posts/post/Post.jsx | 13 ++- src/discussions/posts/post/PostLink.jsx | 9 +- src/discussions/posts/post/PostLink.test.jsx | 2 +- src/discussions/topics/TopicsView.jsx | 2 +- src/discussions/topics/TopicsView.test.jsx | 27 +++--- .../topics/topic-group/TopicGroupBase.jsx | 14 +-- .../topics/topic-group/topic/Topic.jsx | 12 ++- src/discussions/utils.js | 17 +++- 45 files changed, 491 insertions(+), 413 deletions(-) diff --git a/package-lock.json b/package-lock.json index a423120e5..f0d9d4580 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", "@edx/frontend-component-footer": "12.6.0", "@edx/frontend-component-header": "4.10.1", - "@edx/frontend-platform": "4.6.3", + "@edx/frontend-platform": "5.6.1", "@edx/paragon": "20.46.3", "@reduxjs/toolkit": "1.8.0", "@tinymce/tinymce-react": "3.13.1", @@ -27,8 +27,8 @@ "react": "17.0.2", "react-dom": "17.0.2", "react-redux": "7.2.9", - "react-router": "5.2.1", - "react-router-dom": "5.3.0", + "react-router": "6.18.0", + "react-router-dom": "6.18.0", "redux": "4.2.1", "regenerator-runtime": "0.14.0", "timeago.js": "4.0.2", @@ -3529,9 +3529,9 @@ } }, "node_modules/@edx/frontend-platform": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-4.6.3.tgz", - "integrity": "sha512-vvmg2rWfjdOD9BKcHiFlV3n4kVGqMGUYS0UrIk8Dx7BYbb7It03q/twe5b2D3PHQwvNCTei9EgX8+Tn1QhkXBA==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-5.6.1.tgz", + "integrity": "sha512-7MOIjGGYplVY7yHrSea90EkQ24UxKxRKU9FaihB41yUSL/Vin1txDuIn3059Xr+60QfIKRsym+LogXe9IZ47Dw==", "dependencies": { "@cospired/i18n-iso-languages": "4.1.0", "@formatjs/intl-pluralrules": "4.3.3", @@ -3564,7 +3564,7 @@ "react": "^16.9.0 || ^17.0.0", "react-dom": "^16.9.0 || ^17.0.0", "react-redux": "^7.1.1", - "react-router-dom": "^5.0.1", + "react-router-dom": "^6.0.0", "redux": "^4.0.4" } }, @@ -6034,6 +6034,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.11.0.tgz", + "integrity": "sha512-BHdhcWgeiudl91HvVa2wxqZjSHbheSgIiDvxrF1VjFzBzpTtuDPkOdOi3Iqvc08kXtFkLjhbS+ML9aM8mJS+wQ==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@restart/context": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz", @@ -17430,9 +17438,9 @@ } }, "node_modules/jquery": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", - "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", "peer": true }, "node_modules/js-tokens": { @@ -18085,19 +18093,6 @@ "node": ">=4" } }, - "node_modules/mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "dependencies": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - }, - "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, "node_modules/mini-css-extract-plugin": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz", @@ -19044,14 +19039,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -20786,40 +20773,33 @@ } }, "node_modules/react-router": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", - "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", - "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.18.0.tgz", + "integrity": "sha512-vk2y7Dsy8wI02eRRaRmOs9g2o+aE72YCx5q9VasT1N9v+lrdB79tIqrjMfByHiY5+6aYkH2rUa5X839nwWGPDg==", + "dependencies": { + "@remix-run/router": "1.11.0" + }, + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=15" + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", - "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.18.0.tgz", + "integrity": "sha512-Ubrue4+Ercc/BoDkFQfc6og5zRQ4A8YxSO3Knsne+eRbZ+IepAsK249XBH/XaFuOYOYr3L3r13CXTLvYt5JDjw==", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.1", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "@remix-run/router": "1.11.0", + "react-router": "6.18.0" + }, + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=15" + "react": ">=16.8", + "react-dom": ">=16.8" } }, "node_modules/react-style-singleton": { diff --git a/package.json b/package.json index 73044d636..a734a8266 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", "@edx/frontend-component-footer": "12.6.0", "@edx/frontend-component-header": "4.10.1", - "@edx/frontend-platform": "4.6.3", + "@edx/frontend-platform": "5.6.1", "@edx/paragon": "20.46.3", "@reduxjs/toolkit": "1.8.0", "@tinymce/tinymce-react": "3.13.1", @@ -51,8 +51,8 @@ "react": "17.0.2", "react-dom": "17.0.2", "react-redux": "7.2.9", - "react-router": "5.2.1", - "react-router-dom": "5.3.0", + "react-router": "6.18.0", + "react-router-dom": "6.18.0", "redux": "4.2.1", "regenerator-runtime": "0.14.0", "timeago.js": "4.0.2", diff --git a/src/components/TinyMCEEditor.jsx b/src/components/TinyMCEEditor.jsx index 93cc4fcc4..a304c34c3 100644 --- a/src/components/TinyMCEEditor.jsx +++ b/src/components/TinyMCEEditor.jsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Editor } from '@tinymce/tinymce-react'; -import { useLocation, useParams } from 'react-router'; +import { useLocation, useParams } from 'react-router-dom'; // TinyMCE so the global var exists // eslint-disable-next-line no-unused-vars,import/no-extraneous-dependencies import tinymce from 'tinymce/tinymce'; diff --git a/src/data/constants.js b/src/data/constants.js index dc786b439..3fa9496e6 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -147,18 +147,17 @@ export const Routes = { PATH: BASE_PATH, }, LEARNERS: { - PATH: `${BASE_PATH}/learners`, - POSTS: `${BASE_PATH}/learners/:learnerUsername/posts(/:postId)?`, + PATH: `${BASE_PATH}/learners/:learnerUsername?`, + POSTS: `${BASE_PATH}/learners/:learnerUsername/posts/:postId?`, + POSTS_EDIT: `${BASE_PATH}/learners/:learnerUsername/posts/:postId/edit`, }, POSTS: { PATH: `${BASE_PATH}/topics/:topicId`, - MY_POSTS: `${BASE_PATH}/my-posts(/:postId)?`, - ALL_POSTS: `${BASE_PATH}/posts(/:postId)?`, - NEW_POST: [ - `${BASE_PATH}/topics/:topicId/posts/:postId`, - `${BASE_PATH}/topics/:topicId`, - `${BASE_PATH}`, - ], + MY_POSTS: `${BASE_PATH}/my-posts/:postId?`, + ALL_POSTS: `${BASE_PATH}/posts/:postId?`, + EDIT_MY_POSTS: `${BASE_PATH}/my-posts/:postId/edit`, + EDIT_ALL_POSTS: `${BASE_PATH}/posts/:postId/edit`, + NEW_POST: `${BASE_PATH}/*`, EDIT_POST: [ `${BASE_PATH}/category/:category/posts/:postId/edit`, `${BASE_PATH}/topics/:topicId/posts/:postId/edit`, @@ -169,19 +168,19 @@ export const Routes = { }, COMMENTS: { PATH: [ - `${BASE_PATH}/category/:category/posts/:postId`, - `${BASE_PATH}/topics/:topicId/posts/:postId`, + `${BASE_PATH}/category/:category/posts/:postId?`, + `${BASE_PATH}/topics/:topicId/posts/:postId?`, `${BASE_PATH}/posts/:postId`, `${BASE_PATH}/my-posts/:postId`, - `${BASE_PATH}/learners/:learnerUsername/posts/:postId`, + `${BASE_PATH}/learners/:learnerUsername/posts/:postId?`, ], - PAGE: `${BASE_PATH}/:page`, + PAGE: `${BASE_PATH}/:page/*`, PAGES: { - category: `${BASE_PATH}/category/:category/posts/:postId`, - topics: `${BASE_PATH}/topics/:topicId/posts/:postId`, + category: `${BASE_PATH}/category/:category/posts/:postId?`, + topics: `${BASE_PATH}/topics/:topicId/posts/:postId?`, posts: `${BASE_PATH}/posts/:postId`, 'my-posts': `${BASE_PATH}/my-posts/:postId`, - learners: `${BASE_PATH}/learners/:learnerUsername/posts/:postId`, + learners: `${BASE_PATH}/learners/:learnerUsername/posts/:postId?`, }, }, TOPICS: { @@ -192,9 +191,10 @@ export const Routes = { ], ALL: `${BASE_PATH}/topics`, CATEGORY: `${BASE_PATH}/category/:category`, - CATEGORY_POST: `${BASE_PATH}/category/:category/posts/:postId`, + CATEGORY_POST: `${BASE_PATH}/category/:category/posts/:postId?`, + CATEGORY_POST_EDIT: `${BASE_PATH}/category/:category/posts/:postId/edit`, TOPIC: `${BASE_PATH}/topics/:topicId`, - TOPIC_POST: `${BASE_PATH}/topics/:topicId/posts/:postId`, + TOPIC_POST: `${BASE_PATH}/topics/:topicId/posts/:postId?`, TOPIC_POST_EDIT: `${BASE_PATH}/topics/:topicId/posts/:postId/edit`, }, }; @@ -208,11 +208,12 @@ export const PostsPages = { }; export const ALL_ROUTES = [] - .concat([Routes.TOPICS.CATEGORY_POST, Routes.TOPICS.CATEGORY]) + .concat([Routes.TOPICS.CATEGORY_POST, `${Routes.TOPICS.CATEGORY}?`]) .concat(Routes.COMMENTS.PATH) .concat(Routes.TOPICS.PATH) + .concat(Routes.POSTS.EDIT_POST) .concat([Routes.POSTS.ALL_POSTS, Routes.POSTS.MY_POSTS]) .concat([Routes.LEARNERS.POSTS, Routes.LEARNERS.PATH]) - .concat([Routes.DISCUSSIONS.PATH]); + .concat([`${Routes.DISCUSSIONS.PATH}/*`]); export const MAX_UPLOAD_FILE_SIZE = 1024; diff --git a/src/discussions/common/AuthorLabel.jsx b/src/discussions/common/AuthorLabel.jsx index de673bf99..2730b8296 100644 --- a/src/discussions/common/AuthorLabel.jsx +++ b/src/discussions/common/AuthorLabel.jsx @@ -2,8 +2,7 @@ import React, { useContext, useMemo } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { generatePath } from 'react-router'; -import { Link } from 'react-router-dom'; +import { generatePath, Link } from 'react-router-dom'; import * as timeago from 'timeago.js'; import { useIntl } from '@edx/frontend-platform/i18n'; diff --git a/src/discussions/common/HoverCard.test.jsx b/src/discussions/common/HoverCard.test.jsx index 1871c7ffb..437d80883 100644 --- a/src/discussions/common/HoverCard.test.jsx +++ b/src/discussions/common/HoverCard.test.jsx @@ -3,7 +3,7 @@ import { } from '@testing-library/react'; import MockAdapter from 'axios-mock-adapter'; import { IntlProvider } from 'react-intl'; -import { MemoryRouter, Route } from 'react-router'; +import { MemoryRouter } from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; @@ -60,15 +60,12 @@ async function mockAxiosReturnPagedCommentsResponses() { function renderComponent(postId) { const wrapper = render( - + - diff --git a/src/discussions/data/hooks.js b/src/discussions/data/hooks.js index 3389acad7..07d869991 100644 --- a/src/discussions/data/hooks.js +++ b/src/discussions/data/hooks.js @@ -4,7 +4,9 @@ import { } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { useHistory, useLocation, useRouteMatch } from 'react-router'; +import { + matchPath, useLocation, useMatch, useNavigate, +} from 'react-router-dom'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; import { useIntl } from '@edx/frontend-platform/i18n'; @@ -52,16 +54,18 @@ export function useTotalTopicThreadCount() { } export const useSidebarVisible = () => { + const location = useLocation(); const enableInContext = useSelector(selectEnableInContext); - const isViewingTopics = useRouteMatch(Routes.TOPICS.ALL); - const isViewingLearners = useRouteMatch(Routes.LEARNERS.PATH); + const isViewingTopics = useMatch(Routes.TOPICS.ALL); + const isViewingLearners = useMatch(`${Routes.LEARNERS.PATH}/*`); const isFiltered = useSelector(selectAreThreadsFiltered); const totalThreads = useSelector(selectPostThreadCount); const isThreadsEmpty = Boolean(useSelector(threadsLoadingStatus()) === RequestStatus.SUCCESSFUL && !totalThreads); - const isIncontextTopicsView = Boolean(useRouteMatch(Routes.TOPICS.PATH) && enableInContext); - const hideSidebar = Boolean(isThreadsEmpty && !isFiltered && !(isViewingTopics?.isExact || isViewingLearners)); + const matchInContextTopicView = Routes.TOPICS.PATH.find((route) => matchPath({ path: `${route}/*` }, location.pathname)); + const isInContextTopicsView = Boolean(matchInContextTopicView && enableInContext); + const hideSidebar = Boolean(isThreadsEmpty && !isFiltered && !(isViewingTopics || isViewingLearners)); - if (isIncontextTopicsView) { + if (isInContextTopicsView) { return true; } @@ -84,7 +88,7 @@ export function useCourseDiscussionData(courseId) { export function useRedirectToThread(courseId, enableInContextSidebar) { const dispatch = useDispatch(); - const history = useHistory(); + const navigate = useNavigate(); const location = useLocation(); const redirectToThread = useSelector( @@ -101,7 +105,7 @@ export function useRedirectToThread(courseId, enableInContextSidebar) { postId: redirectToThread.threadId, topicId: redirectToThread.topicId, })(location); - history.push(newLocation); + navigate({ ...newLocation }); } }, [redirectToThread]); } diff --git a/src/discussions/discussions-home/DiscussionContent.jsx b/src/discussions/discussions-home/DiscussionContent.jsx index ca3e668c1..420c4c61b 100644 --- a/src/discussions/discussions-home/DiscussionContent.jsx +++ b/src/discussions/discussions-home/DiscussionContent.jsx @@ -1,10 +1,10 @@ import React, { lazy, Suspense } from 'react'; import { useSelector } from 'react-redux'; -import { Route, Switch } from 'react-router'; +import { Route, Routes } from 'react-router-dom'; import Spinner from '../../components/Spinner'; -import { Routes } from '../../data/constants'; +import { Routes as ROUTES } from '../../data/constants'; const PostEditor = lazy(() => import('../posts/post-editor/PostEditor')); const PostCommentsView = lazy(() => import('../post-comments/PostCommentsView')); @@ -16,20 +16,20 @@ const DiscussionContent = () => {
)}> - {postEditorVisible ? ( - - - - ) : ( - - - - - - - - - )} + + {postEditorVisible ? ( + } /> + ) : ( + <> + {ROUTES.POSTS.EDIT_POST.map(route => ( + } /> + ))} + {ROUTES.COMMENTS.PATH.map(route => ( + } /> + ))} + + )} +
diff --git a/src/discussions/discussions-home/DiscussionSidebar.jsx b/src/discussions/discussions-home/DiscussionSidebar.jsx index 66c81633c..f1ef4182a 100644 --- a/src/discussions/discussions-home/DiscussionSidebar.jsx +++ b/src/discussions/discussions-home/DiscussionSidebar.jsx @@ -6,13 +6,13 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { useSelector } from 'react-redux'; import { - Redirect, Route, Switch, useLocation, -} from 'react-router'; + Navigate, Route, Routes, +} from 'react-router-dom'; import { useWindowSize } from '@edx/paragon'; import Spinner from '../../components/Spinner'; -import { RequestStatus, Routes } from '../../data/constants'; +import { RequestStatus, Routes as ROUTES } from '../../data/constants'; import { DiscussionContext } from '../common/context'; import { useContainerSize, useIsOnDesktop, useIsOnXLDesktop, useShowLearnersTab, @@ -27,7 +27,6 @@ const PostsView = lazy(() => import('../posts/PostsView')); const LegacyTopicsView = lazy(() => import('../topics/TopicsView')); const DiscussionSidebar = ({ displaySidebar, postActionBarRef }) => { - const location = useLocation(); const isOnDesktop = useIsOnDesktop(); const isOnXLDesktop = useIsOnXLDesktop(); const { enableInContextSidebar } = useContext(DiscussionContext); @@ -62,47 +61,60 @@ const DiscussionSidebar = ({ displaySidebar, postActionBarRef }) => { data-testid="sidebar" > )}> - + {enableInContext && !enableInContextSidebar && ( - + } + /> )} {enableInContext && !enableInContextSidebar && ( - + [ + ROUTES.TOPICS.TOPIC, + ROUTES.TOPICS.CATEGORY, + ROUTES.TOPICS.TOPIC_POST, + ROUTES.TOPICS.TOPIC_POST_EDIT, + ].map((route) => ( + } + /> + )) )} - - + {[ + ROUTES.POSTS.ALL_POSTS, + ROUTES.POSTS.EDIT_ALL_POSTS, + ROUTES.POSTS.MY_POSTS, + ROUTES.POSTS.EDIT_MY_POSTS, + ROUTES.TOPICS.CATEGORY, + ROUTES.TOPICS.CATEGORY_POST, + ROUTES.TOPICS.CATEGORY_POST_EDIT, + ROUTES.TOPICS.TOPIC, + ROUTES.TOPICS.TOPIC_POST, + ROUTES.TOPICS.TOPIC_POST_EDIT, + ].map((route) => ( + } + /> + ))} + {ROUTES.TOPICS.PATH.map(path => ( + } /> + ))} {redirectToLearnersTab && ( - + [ROUTES.LEARNERS.POSTS, ROUTES.LEARNERS.POSTS_EDIT].map((route) => ( + } /> + )) )} {redirectToLearnersTab && ( - + } /> )} {configStatus === RequestStatus.SUCCESSFUL && ( - + } /> )} - + ); diff --git a/src/discussions/discussions-home/DiscussionSidebar.test.jsx b/src/discussions/discussions-home/DiscussionSidebar.test.jsx index 653f1f492..dda145c82 100644 --- a/src/discussions/discussions-home/DiscussionSidebar.test.jsx +++ b/src/discussions/discussions-home/DiscussionSidebar.test.jsx @@ -3,7 +3,7 @@ import MockAdapter from 'axios-mock-adapter'; import { act } from 'react-dom/test-utils'; import { IntlProvider } from 'react-intl'; import { Context as ResponsiveContext } from 'react-responsive'; -import { MemoryRouter } from 'react-router'; +import { MemoryRouter } from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; @@ -28,8 +28,8 @@ function renderComponent(displaySidebar = true, location = `/${courseId}/`) { const wrapper = render( - - + + diff --git a/src/discussions/discussions-home/DiscussionsHome.jsx b/src/discussions/discussions-home/DiscussionsHome.jsx index a1616722a..83ad198ea 100644 --- a/src/discussions/discussions-home/DiscussionsHome.jsx +++ b/src/discussions/discussions-home/DiscussionsHome.jsx @@ -4,14 +4,14 @@ import React, { lazy, Suspense, useRef } from 'react'; import classNames from 'classnames'; import { useSelector } from 'react-redux'; import { - Route, Switch, useLocation, useRouteMatch, -} from 'react-router'; + matchPath, Route, Routes, useLocation, useMatch, +} from 'react-router-dom'; import { LearningHeader as Header } from '@edx/frontend-component-header'; import { Spinner } from '../../components'; import { selectCourseTabs } from '../../components/NavigationBar/data/selectors'; -import { ALL_ROUTES, DiscussionProvider, Routes } from '../../data/constants'; +import { ALL_ROUTES, DiscussionProvider, Routes as ROUTES } from '../../data/constants'; import { DiscussionContext } from '../common/context'; import { useCourseDiscussionData, useIsOnDesktop, useRedirectToThread, useShowLearnersTab, useSidebarVisible, @@ -40,8 +40,10 @@ const DiscussionsHome = () => { const provider = useSelector(selectDiscussionProvider); const enableInContext = useSelector(selectEnableInContext); const { courseNumber, courseTitle, org } = useSelector(selectCourseTabs); - const { params: { page } } = useRouteMatch(`${Routes.COMMENTS.PAGE}?`); - const { params } = useRouteMatch(ALL_ROUTES); + const pageParams = useMatch(ROUTES.COMMENTS.PAGE)?.params; + const page = pageParams?.page || null; + const matchPattern = ALL_ROUTES.find((route) => matchPath({ path: route }, location.pathname)); + const { params } = useMatch(matchPattern); const isRedirectToLearners = useShowLearnersTab(); const isOnDesktop = useIsOnDesktop(); let displaySidebar = useSidebarVisible(); @@ -95,12 +97,24 @@ const DiscussionsHome = () => { {provider === DiscussionProvider.LEGACY && ( - )}> - - + )}> + + {[ + ROUTES.TOPICS.CATEGORY, + ROUTES.TOPICS.CATEGORY_POST, + ROUTES.TOPICS.CATEGORY_POST_EDIT, + ROUTES.TOPICS.TOPIC, + ROUTES.TOPICS.TOPIC_POST, + ROUTES.TOPICS.TOPIC_POST_EDIT, + ].map((route) => ( + } + /> + ))} + + )}
)}> @@ -112,21 +126,29 @@ const DiscussionsHome = () => { )} {!displayContentArea && ( - - - } - /> - } - /> - {isRedirectToLearners && } - + + <> + {ROUTES.TOPICS.PATH.map(route => ( + : } + /> + ))} + } + /> + {[`${ROUTES.POSTS.PATH}/*`, ROUTES.POSTS.ALL_POSTS, ROUTES.LEARNERS.POSTS].map((route) => ( + } + /> + ))} + {isRedirectToLearners && } />} + + )}
{!enableInContextSidebar && ( diff --git a/src/discussions/discussions-home/DiscussionsHome.test.jsx b/src/discussions/discussions-home/DiscussionsHome.test.jsx index c2fd04b67..804f6413f 100644 --- a/src/discussions/discussions-home/DiscussionsHome.test.jsx +++ b/src/discussions/discussions-home/DiscussionsHome.test.jsx @@ -5,7 +5,7 @@ import MockAdapter from 'axios-mock-adapter'; import { act } from 'react-dom/test-utils'; import { IntlProvider } from 'react-intl'; import { Context as ResponsiveContext } from 'react-responsive'; -import { MemoryRouter } from 'react-router'; +import { MemoryRouter } from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; @@ -42,7 +42,7 @@ function renderComponent(location = `/${courseId}/`) { const wrapper = render( - + diff --git a/src/discussions/empty-posts/EmptyPosts.test.jsx b/src/discussions/empty-posts/EmptyPosts.test.jsx index 6d654a809..88f591b07 100644 --- a/src/discussions/empty-posts/EmptyPosts.test.jsx +++ b/src/discussions/empty-posts/EmptyPosts.test.jsx @@ -26,7 +26,7 @@ function renderComponent(location = `/${courseId}/`) { return render( - + diff --git a/src/discussions/empty-posts/EmptyTopics.jsx b/src/discussions/empty-posts/EmptyTopics.jsx index bcf8e5155..b2420803e 100644 --- a/src/discussions/empty-posts/EmptyTopics.jsx +++ b/src/discussions/empty-posts/EmptyTopics.jsx @@ -1,11 +1,10 @@ import React, { useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { useRouteMatch } from 'react-router'; +import { useParams } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; -import { ALL_ROUTES } from '../../data/constants'; import { useIsOnDesktop, useTotalTopicThreadCount } from '../data/hooks'; import { selectTopicThreadCount } from '../data/selectors'; import messages from '../messages'; @@ -15,11 +14,11 @@ import EmptyPage from './EmptyPage'; const EmptyTopics = () => { const intl = useIntl(); - const match = useRouteMatch(ALL_ROUTES); + const { topicId } = useParams(); const dispatch = useDispatch(); const isOnDesktop = useIsOnDesktop(); const hasGlobalThreads = useTotalTopicThreadCount() > 0; - const topicThreadCount = useSelector(selectTopicThreadCount(match.params.topicId)); + const topicThreadCount = useSelector(selectTopicThreadCount(topicId)); const addPost = useCallback(() => ( dispatch(showPostEditor()) @@ -35,7 +34,7 @@ const EmptyTopics = () => { return null; } - if (match.params.topicId) { + if (topicId) { if (topicThreadCount > 0) { title = messages.noPostSelected; } else { diff --git a/src/discussions/empty-posts/EmptyTopics.test.jsx b/src/discussions/empty-posts/EmptyTopics.test.jsx index 0621c115d..31072a19a 100644 --- a/src/discussions/empty-posts/EmptyTopics.test.jsx +++ b/src/discussions/empty-posts/EmptyTopics.test.jsx @@ -2,14 +2,14 @@ import { render, screen } from '@testing-library/react'; import MockAdapter from 'axios-mock-adapter'; import { IntlProvider } from 'react-intl'; import { Context as ResponsiveContext } from 'react-responsive'; -import { MemoryRouter } from 'react-router'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { AppProvider } from '@edx/frontend-platform/react'; -import { getApiBaseUrl } from '../../data/constants'; +import { getApiBaseUrl, Routes as ROUTES } from '../../data/constants'; import { initializeStore } from '../../store'; import { executeThunk } from '../../test-utils'; import messages from '../messages'; @@ -26,9 +26,12 @@ function renderComponent(location = `/${courseId}/topics/`) { return render( - + - + + } /> + } /> + diff --git a/src/discussions/in-context-topics/TopicPostsView.test.jsx b/src/discussions/in-context-topics/TopicPostsView.test.jsx index f8abeb2d5..0679808a8 100644 --- a/src/discussions/in-context-topics/TopicPostsView.test.jsx +++ b/src/discussions/in-context-topics/TopicPostsView.test.jsx @@ -4,7 +4,9 @@ import { import MockAdapter from 'axios-mock-adapter'; import { act } from 'react-dom/test-utils'; import { IntlProvider } from 'react-intl'; -import { generatePath, MemoryRouter, Route } from 'react-router'; +import { + generatePath, MemoryRouter, Route, Routes, useLocation, +} from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; @@ -12,7 +14,7 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { AppProvider } from '@edx/frontend-platform/react'; import { PostActionsBar } from '../../components'; -import { Routes } from '../../data/constants'; +import { Routes as ROUTES } from '../../data/constants'; import { initializeStore } from '../../store'; import { executeThunk } from '../../test-utils'; import { DiscussionContext } from '../common/context'; @@ -35,16 +37,21 @@ let axiosMock; let lastLocation; let container; +const LocationComponent = () => { + lastLocation = useLocation(); + return null; +}; + async function renderComponent({ topicId, category } = { }) { let path = `/${courseId}/topics`; if (topicId) { - path = generatePath(Routes.POSTS.PATH, { courseId, topicId }); + path = generatePath(ROUTES.POSTS.PATH, { courseId, topicId }); } else if (category) { - path = generatePath(Routes.TOPICS.CATEGORY, { courseId, category }); + path = generatePath(ROUTES.TOPICS.CATEGORY, { courseId, category }); } const wrapper = await render( - + - - - - - - - - { - lastLocation = location; - return null; - }} - /> + + { + [ + ROUTES.POSTS.PATH, + ROUTES.TOPICS.CATEGORY, + ].map((route) => ( + + + + + )} + /> + )) + } + + + + + + )} + /> + diff --git a/src/discussions/in-context-topics/TopicsView.test.jsx b/src/discussions/in-context-topics/TopicsView.test.jsx index f2da48c4a..4cc62c2e5 100644 --- a/src/discussions/in-context-topics/TopicsView.test.jsx +++ b/src/discussions/in-context-topics/TopicsView.test.jsx @@ -5,7 +5,9 @@ import { import MockAdapter from 'axios-mock-adapter'; import { act } from 'react-dom/test-utils'; import { IntlProvider } from 'react-intl'; -import { MemoryRouter, Route } from 'react-router'; +import { + MemoryRouter, Route, Routes, useLocation, +} from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; @@ -32,24 +34,21 @@ let axiosMock; let lastLocation; let container; +const LocationComponent = () => { + lastLocation = useLocation(); + return null; +}; + function renderComponent() { const wrapper = render( - + - - - - - - - { - lastLocation = location; - return null; - }} - /> + + } /> + } /> + diff --git a/src/discussions/in-context-topics/components/BackButton.jsx b/src/discussions/in-context-topics/components/BackButton.jsx index a485013f8..2d28ff3d0 100644 --- a/src/discussions/in-context-topics/components/BackButton.jsx +++ b/src/discussions/in-context-topics/components/BackButton.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { Icon, IconButton, Spinner } from '@edx/paragon'; @@ -12,7 +12,7 @@ import messages from '../messages'; const BackButton = ({ intl, path, title, loading, }) => { - const history = useHistory(); + const navigate = useNavigate(); return ( <> @@ -22,7 +22,7 @@ const BackButton = ({ iconAs={Icon} style={{ padding: '18px' }} size="inline" - onClick={() => history.push(path)} + onClick={() => navigate(path)} alt={intl.formatMessage(messages.backAlt)} />
diff --git a/src/discussions/in-context-topics/components/EmptyTopics.jsx b/src/discussions/in-context-topics/components/EmptyTopics.jsx index ef23c80c1..0f66d3489 100644 --- a/src/discussions/in-context-topics/components/EmptyTopics.jsx +++ b/src/discussions/in-context-topics/components/EmptyTopics.jsx @@ -1,11 +1,10 @@ import React, { useCallback, useContext } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { useRouteMatch } from 'react-router'; +import { useParams } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; -import { ALL_ROUTES } from '../../../data/constants'; import { DiscussionContext } from '../../common/context'; import { useIsOnDesktop } from '../../data/hooks'; import { selectPostThreadCount } from '../../data/selectors'; @@ -16,11 +15,11 @@ import { selectCourseWareThreadsCount, selectTotalTopicsThreadsCount } from '../ const EmptyTopics = () => { const intl = useIntl(); - const match = useRouteMatch(ALL_ROUTES); + const { category, topicId } = useParams(); const dispatch = useDispatch(); const isOnDesktop = useIsOnDesktop(); const { enableInContextSidebar } = useContext(DiscussionContext); - const courseWareThreadsCount = useSelector(selectCourseWareThreadsCount(match.params.category)); + const courseWareThreadsCount = useSelector(selectCourseWareThreadsCount(category)); const topicThreadsCount = useSelector(selectPostThreadCount); // hasGlobalThreads is used to determine if there are any post available in courseware and non-courseware topics const hasGlobalThreads = useSelector(selectTotalTopicsThreadsCount) > 0; @@ -39,7 +38,7 @@ const EmptyTopics = () => { return null; } - if (match.params.topicId) { + if (topicId) { if (topicThreadsCount > 0) { title = messages.noPostSelected; } else { @@ -48,7 +47,7 @@ const EmptyTopics = () => { subTitle = messages.emptyTopic; fullWidth = true; } - } else if (match.params.category) { + } else if (category) { if (enableInContextSidebar && topicThreadsCount > 0) { title = messages.noPostSelected; } else if (courseWareThreadsCount > 0) { diff --git a/src/discussions/in-context-topics/topic/SectionBaseGroup.jsx b/src/discussions/in-context-topics/topic/SectionBaseGroup.jsx index 667eeeeea..faca47362 100644 --- a/src/discussions/in-context-topics/topic/SectionBaseGroup.jsx +++ b/src/discussions/in-context-topics/topic/SectionBaseGroup.jsx @@ -2,8 +2,7 @@ import React, { useCallback, useMemo } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { useParams } from 'react-router'; -import { Link } from 'react-router-dom'; +import { Link, useParams } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; @@ -41,7 +40,7 @@ const SectionBaseGroup = ({ role="option" data-subsection-id={subsection.id} data-testid="subsection-group" - to={sectionUrl(subsection.id)} + to={sectionUrl(subsection.id)()} onClick={() => isSelected(subsection.id)} aria-current={isSelected(section.id) ? 'page' : undefined} tabIndex={(isSelected(subsection.id) || index === 0) ? 0 : -1} diff --git a/src/discussions/in-context-topics/topic/Topic.jsx b/src/discussions/in-context-topics/topic/Topic.jsx index 39b160839..b4f955861 100644 --- a/src/discussions/in-context-topics/topic/Topic.jsx +++ b/src/discussions/in-context-topics/topic/Topic.jsx @@ -5,8 +5,7 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { useSelector } from 'react-redux'; -import { useParams } from 'react-router'; -import { Link } from 'react-router-dom'; +import { Link, useParams } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; import { Icon, OverlayTrigger, Tooltip } from '@edx/paragon'; @@ -42,7 +41,7 @@ const Topic = ({ 'border-light-400 border-bottom': showDivider, })} data-topic-id={topic.id} - to={topicUrl} + to={topicUrl()} onClick={() => isSelected(topic.id)} aria-current={isSelected(topic.id) ? 'page' : undefined} role="option" diff --git a/src/discussions/learners/LearnerPostsView.jsx b/src/discussions/learners/LearnerPostsView.jsx index a49890093..48f819360 100644 --- a/src/discussions/learners/LearnerPostsView.jsx +++ b/src/discussions/learners/LearnerPostsView.jsx @@ -4,7 +4,7 @@ import React, { import capitalize from 'lodash/capitalize'; import { useDispatch, useSelector } from 'react-redux'; -import { useHistory, useLocation } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; import { @@ -35,7 +35,7 @@ import messages from './messages'; const LearnerPostsView = () => { const intl = useIntl(); const location = useLocation(); - const history = useHistory(); + const navigate = useNavigate(); const dispatch = useDispatch(); const postsIds = useSelector(selectAllThreadsIds); @@ -83,7 +83,7 @@ const LearnerPostsView = () => { iconAs={Icon} style={{ padding: '18px' }} size="inline" - onClick={() => history.push(discussionsPath(Routes.LEARNERS.PATH, { courseId })(location))} + onClick={() => navigate({ ...discussionsPath(Routes.LEARNERS.PATH, { courseId })(location) })} alt={intl.formatMessage(messages.back)} />
diff --git a/src/discussions/learners/LearnerPostsView.test.jsx b/src/discussions/learners/LearnerPostsView.test.jsx index 62d094679..cee5d14df 100644 --- a/src/discussions/learners/LearnerPostsView.test.jsx +++ b/src/discussions/learners/LearnerPostsView.test.jsx @@ -6,7 +6,9 @@ import { import MockAdapter from 'axios-mock-adapter'; import { act } from 'react-dom/test-utils'; import { IntlProvider } from 'react-intl'; -import { MemoryRouter, Route } from 'react-router'; +import { + MemoryRouter, Route, Routes, useLocation, +} from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; @@ -33,26 +35,26 @@ const username = 'abc123'; let container; let lastLocation; +const LocationComponent = () => { + lastLocation = useLocation(); + return null; +}; + async function renderComponent() { const wrapper = render( - + - - - - { - lastLocation = location; - return null; - }} - /> + + } /> + diff --git a/src/discussions/learners/LearnersView.jsx b/src/discussions/learners/LearnersView.jsx index 51e58a30e..7483f3b06 100644 --- a/src/discussions/learners/LearnersView.jsx +++ b/src/discussions/learners/LearnersView.jsx @@ -1,15 +1,13 @@ import React, { useCallback, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { - Redirect, useLocation, useParams, -} from 'react-router'; +import { useParams } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; import { Button, Spinner } from '@edx/paragon'; import SearchInfo from '../../components/SearchInfo'; -import { RequestStatus, Routes } from '../../data/constants'; +import { RequestStatus } from '../../data/constants'; import { selectConfigLoadingStatus, selectLearnersTabEnabled } from '../data/selectors'; import NoResults from '../posts/NoResults'; import { @@ -27,7 +25,6 @@ import messages from './messages'; const LearnersView = () => { const intl = useIntl(); const { courseId } = useParams(); - const location = useLocation(); const dispatch = useDispatch(); const orderBy = useSelector(selectLearnerSorting()); const nextPage = useSelector(selectLearnerNextPage()); @@ -83,14 +80,6 @@ const LearnersView = () => { /> )}
- {courseConfigLoadingStatus === RequestStatus.SUCCESSFUL && !learnersTabEnabled && ( - - )} {renderLearnersList} {loadingStatus === RequestStatus.IN_PROGRESS ? (
diff --git a/src/discussions/learners/LearnersView.test.jsx b/src/discussions/learners/LearnersView.test.jsx index 712f066c6..183ba07e0 100644 --- a/src/discussions/learners/LearnersView.test.jsx +++ b/src/discussions/learners/LearnersView.test.jsx @@ -7,7 +7,7 @@ import { import MockAdapter from 'axios-mock-adapter'; import { act } from 'react-dom/test-utils'; import { IntlProvider } from 'react-intl'; -import { MemoryRouter, Route } from 'react-router'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; @@ -34,7 +34,7 @@ let container; function renderComponent() { const wrapper = render( - + - - - - + + + + + + )} + /> + diff --git a/src/discussions/learners/learner-post-filter-bar/LearnerPostFilterBar.test.jsx b/src/discussions/learners/learner-post-filter-bar/LearnerPostFilterBar.test.jsx index d4281557f..6dd45c250 100644 --- a/src/discussions/learners/learner-post-filter-bar/LearnerPostFilterBar.test.jsx +++ b/src/discussions/learners/learner-post-filter-bar/LearnerPostFilterBar.test.jsx @@ -5,12 +5,10 @@ import { waitFor, } from '@testing-library/react'; import { IntlProvider } from 'react-intl'; -import { generatePath, MemoryRouter, Route } from 'react-router'; import { initializeMockApp } from '@edx/frontend-platform'; import { AppProvider } from '@edx/frontend-platform/react'; -import { Routes } from '../../../data/constants'; import { initializeStore } from '../../../store'; import { DiscussionContext } from '../../common/context'; import LearnerPostFilterBar from './LearnerPostFilterBar'; @@ -18,32 +16,21 @@ import LearnerPostFilterBar from './LearnerPostFilterBar'; let store; const username = 'abc123'; const courseId = 'course-v1:edX+DemoX+Demo_Course'; -const path = generatePath( - Routes.LEARNERS.POSTS, - { courseId, learnerUsername: username }, -); -function renderComponent() { - return render( - - - - - - - - - , - ); -} +const renderComponent = () => render( + + + + + + + , +); describe('LearnerPostFilterBar', () => { beforeEach(async () => { diff --git a/src/discussions/learners/learner/LearnerCard.jsx b/src/discussions/learners/learner/LearnerCard.jsx index 97acb808a..8304cd6c4 100644 --- a/src/discussions/learners/learner/LearnerCard.jsx +++ b/src/discussions/learners/learner/LearnerCard.jsx @@ -18,7 +18,7 @@ const LearnerCard = ({ learner }) => { 0: enableInContextSidebar ? 'in-context' : undefined, learnerUsername: learner.username, courseId, - }); + })(); return ( {showAllMsg} @@ -39,7 +39,7 @@ const BreadcrumbDropdown = ({ key={itemLabelFunc(item)} active={itemActiveFunc(item)} as={Link} - to={itemPathFunc(item)} + to={itemPathFunc(item)()} > {itemLabelFunc(item)} diff --git a/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.jsx b/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.jsx index f9ad455e2..06b53c7a0 100644 --- a/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.jsx +++ b/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.jsx @@ -1,7 +1,7 @@ import React, { useCallback } from 'react'; import { useSelector } from 'react-redux'; -import { useRouteMatch } from 'react-router'; +import { useParams } from 'react-router-dom'; import { Routes } from '../../../data/constants'; import { @@ -15,12 +15,10 @@ import BreadcrumbDropdown from './BreadcrumbDropdown'; const LegacyBreadcrumbMenu = () => { const { - params: { - courseId, - category, - topicId: currentTopicId, - }, - } = useRouteMatch([Routes.TOPICS.CATEGORY, Routes.TOPICS.TOPIC]); + courseId, + category, + topicId: currentTopicId, + } = useParams(); const currentTopic = useSelector(selectTopic(currentTopicId)); const currentCategory = category || currentTopic?.categoryId; const decodedCurrentCategory = String(currentCategory).replace('%23', '#'); diff --git a/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.test.jsx b/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.test.jsx index 1e9e9e089..e0eda57d7 100644 --- a/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.test.jsx +++ b/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.test.jsx @@ -5,14 +5,14 @@ import { } from '@testing-library/react'; import MockAdapter from 'axios-mock-adapter'; import { IntlProvider } from 'react-intl'; -import { MemoryRouter, Route } from 'react-router'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { AppProvider } from '@edx/frontend-platform/react'; -import { getApiBaseUrl, Routes } from '../../../data/constants'; +import { getApiBaseUrl, Routes as ROUTES } from '../../../data/constants'; import { initializeStore } from '../../../store'; import { executeThunk } from '../../../test-utils'; import { fetchCourseTopics } from '../../topics/data/thunks'; @@ -28,15 +28,22 @@ let axiosMock; function renderComponent(path) { render( - + - + + { + [ + ROUTES.POSTS.PATH, + ROUTES.TOPICS.CATEGORY, + ].map((route) => ( + } + /> + )) + } + , diff --git a/src/discussions/navigation/navigation-bar/NavigationBar.jsx b/src/discussions/navigation/navigation-bar/NavigationBar.jsx index dd7ea886b..dd6a715b1 100644 --- a/src/discussions/navigation/navigation-bar/NavigationBar.jsx +++ b/src/discussions/navigation/navigation-bar/NavigationBar.jsx @@ -1,7 +1,6 @@ import React, { useContext, useMemo } from 'react'; -import { matchPath } from 'react-router'; -import { NavLink } from 'react-router-dom'; +import { matchPath, NavLink, useLocation } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; import { Nav } from '@edx/paragon'; @@ -16,6 +15,8 @@ const NavigationBar = () => { const intl = useIntl(); const { courseId } = useContext(DiscussionContext); const showLearnersTab = useShowLearnersTab(); + const location = useLocation(); + const isTopicsNavActive = Boolean(matchPath({ path: `${Routes.TOPICS.CATEGORY}/*` }, location.pathname)); const navLinks = useMemo(() => ([ { @@ -28,7 +29,6 @@ const NavigationBar = () => { }, { route: Routes.TOPICS.ALL, - isActive: (match, location) => Boolean(matchPath(location.pathname, { path: Routes.TOPICS.PATH })), labelMessage: messages.allTopics, }, ]), []); @@ -49,8 +49,8 @@ const NavigationBar = () => { {intl.formatMessage(link.labelMessage)} diff --git a/src/discussions/post-comments/PostCommentsView.jsx b/src/discussions/post-comments/PostCommentsView.jsx index f44a0bf69..4407b5711 100644 --- a/src/discussions/post-comments/PostCommentsView.jsx +++ b/src/discussions/post-comments/PostCommentsView.jsx @@ -2,14 +2,16 @@ import React, { Suspense, useCallback, useContext, useEffect, useState, } from 'react'; -import { useHistory, useLocation } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; import { Button, Icon, IconButton } from '@edx/paragon'; import { ArrowBack } from '@edx/paragon/icons'; import Spinner from '../../components/Spinner'; -import { EndorsementStatus, PostsPages, ThreadType } from '../../data/constants'; +import { + EndorsementStatus, PostsPages, ThreadType, +} from '../../data/constants'; import { useDispatchWithState } from '../../data/hooks'; import { DiscussionContext } from '../common/context'; import { useIsOnDesktop } from '../data/hooks'; @@ -27,7 +29,7 @@ const CommentsView = React.lazy(() => import('./comments/CommentsView')); const PostCommentsView = () => { const intl = useIntl(); - const history = useHistory(); + const navigate = useNavigate(); const location = useLocation(); const isOnDesktop = useIsOnDesktop(); const [addingResponse, setAddingResponse] = useState(false); @@ -37,6 +39,9 @@ const PostCommentsView = () => { } = useContext(DiscussionContext); const commentsCount = useCommentsCount(postId); const { closed, id: threadId, type } = usePost(postId); + const redirectUrl = discussionsPath(PostsPages[page], { + courseId, learnerUsername, category, topicId, + })(location); useEffect(() => { if (!threadId) { @@ -89,9 +94,7 @@ const PostCommentsView = () => { variant="plain" className="px-0 line-height-24 py-0 my-1.5 border-0 font-weight-normal font-style text-primary-500" iconBefore={ArrowBack} - onClick={() => history.push(discussionsPath(PostsPages[page], { - courseId, learnerUsername, category, topicId, - })(location))} + onClick={() => navigate({ ...redirectUrl })} size="sm" > {intl.formatMessage(messages.backAlt)} @@ -106,9 +109,7 @@ const PostCommentsView = () => { style={{ padding: '18px' }} size="inline" className="ml-4 mt-4" - onClick={() => history.push(discussionsPath(PostsPages[page], { - courseId, learnerUsername, category, topicId, - })(location))} + onClick={() => navigate({ ...redirectUrl })} alt={intl.formatMessage(messages.backAlt)} /> ) diff --git a/src/discussions/post-comments/PostCommentsView.test.jsx b/src/discussions/post-comments/PostCommentsView.test.jsx index 07540f4ae..3bee05c2f 100644 --- a/src/discussions/post-comments/PostCommentsView.test.jsx +++ b/src/discussions/post-comments/PostCommentsView.test.jsx @@ -3,7 +3,9 @@ import { } from '@testing-library/react'; import MockAdapter from 'axios-mock-adapter'; import { IntlProvider } from 'react-intl'; -import { MemoryRouter, Route } from 'react-router'; +import { + MemoryRouter, Route, Routes, useLocation, +} from 'react-router-dom'; import { Factory } from 'rosie'; import { camelCaseObject, initializeMockApp } from '@edx/frontend-platform'; @@ -106,22 +108,28 @@ async function setupCourseConfig() { await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState); } -function renderComponent(postId, isClosed = false) { +const LocationComponent = () => { + testLocation = useLocation(); + return null; +}; + +function renderComponent(postId, isClosed = false, page = 'posts', path = `/${courseId}/posts/${postId}`) { const wrapper = render( - + - + - { - testLocation = location; - return null; - }} - /> + + } + /> + @@ -427,6 +435,28 @@ describe('ThreadView', () => { expect(testLocation.pathname).toBe(`/${courseId}/posts/${discussionPostId}/edit`); }); + it('should show the editor if the post is edited on topics page', async () => { + await setupCourseConfig(false); + await waitFor(() => renderComponent( + discussionPostId, + false, + 'topics', + `/${courseId}/topics/topic-id/posts/${discussionPostId}`, + )); + + const post = await screen.findByTestId('post-thread-1'); + const hoverCard = within(post).getByTestId('hover-card-thread-1'); + await act(async () => { + fireEvent.click( + within(hoverCard).getByRole('button', { name: /actions menu/i }), + ); + }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /edit/i })); + }); + expect(testLocation.pathname).toBe(`/${courseId}/topics/topic-id/posts/${discussionPostId}/edit`); + }); + it('should allow pinning the post', async () => { await waitFor(() => renderComponent(discussionPostId)); const post = await screen.findByTestId('post-thread-1'); diff --git a/src/discussions/posts/NoResults.test.jsx b/src/discussions/posts/NoResults.test.jsx index 78dc4eea2..0a92667c7 100644 --- a/src/discussions/posts/NoResults.test.jsx +++ b/src/discussions/posts/NoResults.test.jsx @@ -21,7 +21,7 @@ function renderComponent(location = `/${courseId}/`) { return render( - + diff --git a/src/discussions/posts/PostsView.test.jsx b/src/discussions/posts/PostsView.test.jsx index 7cc1efb15..d420270c7 100644 --- a/src/discussions/posts/PostsView.test.jsx +++ b/src/discussions/posts/PostsView.test.jsx @@ -5,15 +5,15 @@ import MockAdapter from 'axios-mock-adapter'; import { act } from 'react-dom/test-utils'; import { IntlProvider } from 'react-intl'; import { - generatePath, MemoryRouter, Route, Switch, -} from 'react-router'; + generatePath, MemoryRouter, Route, Routes, +} from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { AppProvider } from '@edx/frontend-platform/react'; -import { getApiBaseUrl, Routes, ThreadType } from '../../data/constants'; +import { getApiBaseUrl, Routes as ROUTES, ThreadType } from '../../data/constants'; import { initializeStore } from '../../store'; import { executeThunk } from '../../test-utils'; import { getCohortsApiUrl } from '../cohorts/data/api'; @@ -39,24 +39,24 @@ const username = 'abc123'; async function renderComponent({ postId, topicId, category, myPosts, enableInContextSidebar = false, } = { myPosts: false }) { - let path = generatePath(Routes.POSTS.ALL_POSTS, { courseId }); - let page; + let path = generatePath(ROUTES.POSTS.ALL_POSTS, { courseId }); + let page = 'posts'; if (postId) { - path = generatePath(Routes.POSTS.ALL_POSTS, { courseId, postId }); + path = generatePath(ROUTES.POSTS.ALL_POSTS, { courseId, postId }); page = 'posts'; } else if (topicId) { - path = generatePath(Routes.POSTS.PATH, { courseId, topicId }); - page = 'posts'; + path = generatePath(ROUTES.POSTS.PATH, { courseId, topicId }); + page = 'topics'; } else if (category) { - path = generatePath(Routes.TOPICS.CATEGORY, { courseId, category }); + path = generatePath(ROUTES.TOPICS.CATEGORY, { courseId, category }); page = 'category'; } else if (myPosts) { - path = generatePath(Routes.POSTS.MY_POSTS, { courseId }); + path = generatePath(ROUTES.POSTS.MY_POSTS, { courseId }); page = 'my-posts'; } await render( - + - - - - - - + + { + [ + ROUTES.POSTS.PATH, + ROUTES.POSTS.MY_POSTS, + ROUTES.POSTS.ALL_POSTS, + ROUTES.TOPICS.CATEGORY, + ].map((route) => ( + } /> + )) + } + diff --git a/src/discussions/posts/post-editor/PostEditor.jsx b/src/discussions/posts/post-editor/PostEditor.jsx index 8a15ca8aa..e626c3581 100644 --- a/src/discussions/posts/post-editor/PostEditor.jsx +++ b/src/discussions/posts/post-editor/PostEditor.jsx @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import { Formik } from 'formik'; import { isEmpty } from 'lodash'; import { useDispatch, useSelector } from 'react-redux'; -import { useHistory, useLocation, useParams } from 'react-router-dom'; +import { useLocation, useNavigate, useParams } from 'react-router-dom'; import * as Yup from 'yup'; import { useIntl } from '@edx/frontend-platform/i18n'; @@ -55,7 +55,7 @@ const PostEditor = ({ editExisting, }) => { const intl = useIntl(); - const history = useHistory(); + const navigate = useNavigate(); const location = useLocation(); const dispatch = useDispatch(); const editorRef = useRef(null); @@ -126,7 +126,7 @@ const PostEditor = ({ learnerUsername: post?.author, category, })(location); - history.push(newLocation); + navigate({ ...newLocation }); } dispatch(hidePostEditor()); }, [postId, topicId, post?.author, category, editExisting, commentsPagePath, location]); diff --git a/src/discussions/posts/post-editor/PostEditor.test.jsx b/src/discussions/posts/post-editor/PostEditor.test.jsx index 49a15693d..ff75a5bdf 100644 --- a/src/discussions/posts/post-editor/PostEditor.test.jsx +++ b/src/discussions/posts/post-editor/PostEditor.test.jsx @@ -7,14 +7,14 @@ import userEvent from '@testing-library/user-event'; import MockAdapter from 'axios-mock-adapter'; import { act } from 'react-dom/test-utils'; import { IntlProvider } from 'react-intl'; -import { MemoryRouter, Route } from 'react-router'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { Factory } from 'rosie'; import { initializeMockApp } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { AppProvider } from '@edx/frontend-platform/react'; -import { getApiBaseUrl, Routes } from '../../../data/constants'; +import { getApiBaseUrl, Routes as ROUTES } from '../../../data/constants'; import { initializeStore } from '../../../store'; import { executeThunk } from '../../../test-utils'; import { getCohortsApiUrl } from '../../cohorts/data/api'; @@ -37,17 +37,19 @@ let axiosMock; let container; async function renderComponent(editExisting = false, location = `/${courseId}/posts/`) { - const path = editExisting ? Routes.POSTS.EDIT_POST : Routes.POSTS.NEW_POSTS; + const paths = editExisting ? ROUTES.POSTS.EDIT_POST : [ROUTES.POSTS.NEW_POST]; const wrapper = await render( - + - - - + + {paths.map((path) => ( + } /> + ))} + diff --git a/src/discussions/posts/post/Post.jsx b/src/discussions/posts/post/Post.jsx index 721397bbf..7e5464002 100644 --- a/src/discussions/posts/post/Post.jsx +++ b/src/discussions/posts/post/Post.jsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { toString } from 'lodash'; import { useDispatch, useSelector } from 'react-redux'; -import { useHistory, useLocation } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; import { getConfig } from '@edx/frontend-platform'; import { useIntl } from '@edx/frontend-platform/i18n'; @@ -19,6 +19,7 @@ import HoverCard from '../../common/HoverCard'; import { ContentTypes } from '../../data/constants'; import { selectUserHasModerationPrivileges } from '../../data/selectors'; import { selectTopic } from '../../topics/data/selectors'; +import { truncatePath } from '../../utils'; import { selectThread } from '../data/selectors'; import { removeThread, updateExistingThread } from '../data/thunks'; import ClosePostReasonModal from './ClosePostReasonModal'; @@ -35,7 +36,7 @@ const Post = ({ handleAddResponseButton }) => { } = useSelector(selectThread(postId)); const intl = useIntl(); const location = useLocation(); - const history = useHistory(); + const navigate = useNavigate(); const dispatch = useDispatch(); const { courseId } = useContext(DiscussionContext); const topic = useSelector(selectTopic(topicId)); @@ -48,9 +49,11 @@ const Post = ({ handleAddResponseButton }) => { const displayPostFooter = following || voteCount || closed || (groupId && userHasModerationPrivileges); const handleDeleteConfirmation = useCallback(async () => { + const basePath = truncatePath(location.pathname); + await dispatch(removeThread(postId)); - history.push({ - pathname: '.', + navigate({ + pathname: basePath, search: enableInContextSidebar && '?inContextSidebar', }); hideDeleteConfirmation(); @@ -61,7 +64,7 @@ const Post = ({ handleAddResponseButton }) => { hideReportConfirmation(); }, [abuseFlagged, postId, hideReportConfirmation]); - const handlePostContentEdit = useCallback(() => history.push({ + const handlePostContentEdit = useCallback(() => navigate({ ...location, pathname: `${location.pathname}/edit`, }), [location.pathname]); diff --git a/src/discussions/posts/post/PostLink.jsx b/src/discussions/posts/post/PostLink.jsx index 5db61bf9c..5035c35fa 100644 --- a/src/discussions/posts/post/PostLink.jsx +++ b/src/discussions/posts/post/PostLink.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { useSelector } from 'react-redux'; -import { Link } from 'react-router-dom'; +import { Link, useLocation } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; import { Badge, Icon } from '@edx/paragon'; @@ -25,6 +25,7 @@ const PostLink = ({ showDivider, }) => { const intl = useIntl(); + const { search } = useLocation(); const { courseId, postId: selectedPostId, @@ -37,14 +38,14 @@ const PostLink = ({ topicId, hasEndorsed, type, author, authorLabel, abuseFlagged, abuseFlaggedCount, read, commentCount, unreadCommentCount, id, pinned, previewBody, title, voted, voteCount, following, groupId, groupName, createdAt, } = useSelector(selectThread(postId)); - const linkUrl = discussionsPath(Routes.COMMENTS.PAGES[page], { + const { pathname } = discussionsPath(Routes.COMMENTS.PAGES[page], { 0: enableInContextSidebar ? 'in-context' : undefined, courseId, topicId, postId, category, learnerUsername, - }); + })(); const showAnsweredBadge = hasEndorsed && type === ThreadType.QUESTION; const authorLabelColor = AvatarOutlineAndLabelColors[authorLabel]; const canSeeReportedBadge = abuseFlagged || abuseFlaggedCount; @@ -63,7 +64,7 @@ const PostLink = ({ 'border-bottom border-light-400': showDivider, }) } - to={linkUrl} + to={`${pathname}${enableInContextSidebar ? search : ''}`} aria-current={checkIsSelected ? 'page' : undefined} role="option" tabIndex={(checkIsSelected || idx === 0) ? 0 : -1} diff --git a/src/discussions/posts/post/PostLink.test.jsx b/src/discussions/posts/post/PostLink.test.jsx index d37293673..42c068ec9 100644 --- a/src/discussions/posts/post/PostLink.test.jsx +++ b/src/discussions/posts/post/PostLink.test.jsx @@ -49,7 +49,7 @@ function renderComponent(id) { return render( - + { + lastLocation = useLocation(); + return null; +}; + function renderComponent() { const wrapper = render( - + - - - - - - - { - lastLocation = location; - return null; - }} - /> + + } /> + } /> + diff --git a/src/discussions/topics/topic-group/TopicGroupBase.jsx b/src/discussions/topics/topic-group/TopicGroupBase.jsx index 18eed076f..08861e49f 100644 --- a/src/discussions/topics/topic-group/TopicGroupBase.jsx +++ b/src/discussions/topics/topic-group/TopicGroupBase.jsx @@ -2,7 +2,7 @@ import React, { useContext, useMemo } from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; -import { Link } from 'react-router-dom'; +import { Link, useLocation } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; @@ -20,10 +20,15 @@ const TopicGroupBase = ({ topicsIds, }) => { const intl = useIntl(); - const { courseId } = useContext(DiscussionContext); + const { search } = useLocation(); + const { courseId, enableInContextSidebar } = useContext(DiscussionContext); const filter = useSelector(selectTopicFilter); const topics = useSelector(selectTopicsById(topicsIds)); const hasTopics = topics.length > 0; + const { pathname } = discussionsPath(Routes.TOPICS.CATEGORY, { + courseId, + category: groupId, + })(); const matchesFilter = useMemo(() => ( filter ? groupTitle?.toLowerCase().includes(filter) : true @@ -69,10 +74,7 @@ const TopicGroupBase = ({ {linkToGroup && groupId ? ( {groupTitle} diff --git a/src/discussions/topics/topic-group/topic/Topic.jsx b/src/discussions/topics/topic-group/topic/Topic.jsx index 6e4ed220f..838998e9d 100644 --- a/src/discussions/topics/topic-group/topic/Topic.jsx +++ b/src/discussions/topics/topic-group/topic/Topic.jsx @@ -1,18 +1,18 @@ /* eslint-disable react/prop-types */ /* eslint-disable no-unused-vars, react/forbid-prop-types */ -import React, { useCallback } from 'react'; +import React, { useCallback, useContext } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { useSelector } from 'react-redux'; -import { useParams } from 'react-router'; -import { Link } from 'react-router-dom'; +import { Link, useLocation, useParams } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; import { Icon, OverlayTrigger, Tooltip } from '@edx/paragon'; import { HelpOutline, PostOutline, Report } from '@edx/paragon/icons'; import { Routes } from '../../../../data/constants'; +import { DiscussionContext } from '../../../common/context'; import { selectUserHasModerationPrivileges, selectUserIsGroupTa } from '../../../data/selectors'; import { discussionsPath } from '../../../utils'; import { selectTopic } from '../../data/selectors'; @@ -20,6 +20,8 @@ import messages from '../../messages'; const Topic = ({ topicId, showDivider, index }) => { const intl = useIntl(); + const { search } = useLocation(); + const { enableInContextSidebar } = useContext(DiscussionContext); const { courseId } = useParams(); const topic = useSelector(selectTopic(topicId)); const { @@ -28,7 +30,7 @@ const Topic = ({ topicId, showDivider, index }) => { const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges); const userIsGroupTa = useSelector(selectUserIsGroupTa); const canSeeReportedStats = (activeFlags || inactiveFlags) && (userHasModerationPrivileges || userIsGroupTa); - const topicUrl = discussionsPath(Routes.TOPICS.TOPIC, { courseId, topicId }); + const { pathname } = discussionsPath(Routes.TOPICS.TOPIC, { courseId, topicId })(); const isSelected = useCallback((selectedId) => ( window.location.pathname.includes(selectedId) @@ -42,7 +44,7 @@ const Topic = ({ topicId, showDivider, index }) => { }) } data-topic-id={id} - to={topicUrl} + to={`${pathname}${enableInContextSidebar ? search : ''}`} onClick={() => isSelected(id)} aria-current={isSelected(id) ? 'page' : undefined} role="option" diff --git a/src/discussions/utils.js b/src/discussions/utils.js index b7c45ba4f..64e0eb8cb 100644 --- a/src/discussions/utils.js +++ b/src/discussions/utils.js @@ -3,7 +3,9 @@ import { useCallback, useContext, useMemo } from 'react'; import { getIn } from 'formik'; import { uniqBy } from 'lodash'; import { useSelector } from 'react-redux'; -import { generatePath, useRouteMatch } from 'react-router'; +import { + generatePath, matchPath, useLocation, +} from 'react-router-dom'; import { getConfig } from '@edx/frontend-platform'; import { @@ -11,7 +13,9 @@ import { } from '@edx/paragon/icons'; import { InsertLink } from '../components/icons'; -import { ContentActions, Routes, ThreadType } from '../data/constants'; +import { + ContentActions, Routes, ThreadType, +} from '../data/constants'; import { ContentSelectors } from './data/constants'; import { PostCommentsContext } from './post-comments/postCommentsContext'; import messages from './messages'; @@ -42,8 +46,9 @@ export function isFormikFieldInvalid(field, { * @returns {string} */ export function useCommentsPagePath() { - const { params } = useRouteMatch(Routes.COMMENTS.PAGE); - return Routes.COMMENTS.PAGES[params.page]; + const location = useLocation(); + const { params: { page } } = matchPath({ path: Routes.COMMENTS.PAGE }, location.pathname); + return Routes.COMMENTS.PAGES[page]; } /** @@ -284,3 +289,7 @@ export function handleKeyDown(event) { export function isLastElementOfList(list, element) { return list[list.length - 1] === element; } + +export function truncatePath(path) { + return path.substring(0, path.lastIndexOf('/')); +} From 1d89e9556abad972608bd03788645afde951bf03 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:11:01 +0500 Subject: [PATCH 11/18] fix(deps): update dependency @edx/frontend-component-footer to v12.6.1 (#625) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 73 +++++++++++++++++++++++++++++++++++++++++------ package.json | 2 +- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index f0d9d4580..5fb6da815 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "AGPL-3.0", "dependencies": { "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", - "@edx/frontend-component-footer": "12.6.0", + "@edx/frontend-component-footer": "12.6.1", "@edx/frontend-component-header": "4.10.1", "@edx/frontend-platform": "5.6.1", "@edx/paragon": "20.46.3", @@ -3126,15 +3126,15 @@ } }, "node_modules/@edx/frontend-component-footer": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.6.0.tgz", - "integrity": "sha512-s+YwcThkETBcyRji2Zl7CTYebrsqevP0rmTYyycEL952HkpbQ7EY8Ym0wYH2sp/ZnZ9bTyEeWsiQS5l7eMyY1A==", + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.6.1.tgz", + "integrity": "sha512-Wjqv1kJ3KaQTFmVVhU2mNuKRSnocNt2j7bDd8RxbZU/UfUM6LxOy1CGbkCAG0xtCnc/n5+1zHJJ/aDX0ak7viA==", "dependencies": { "@edx/paragon": "^21.3.1", - "@fortawesome/fontawesome-svg-core": "6.4.2", - "@fortawesome/free-brands-svg-icons": "6.4.2", - "@fortawesome/free-regular-svg-icons": "6.4.2", - "@fortawesome/free-solid-svg-icons": "6.4.2", + "@fortawesome/fontawesome-svg-core": "6.5.1", + "@fortawesome/free-brands-svg-icons": "6.5.1", + "@fortawesome/free-regular-svg-icons": "6.5.1", + "@fortawesome/free-solid-svg-icons": "6.5.1", "@fortawesome/react-fontawesome": "0.2.0", "lodash": "^4.17.21" }, @@ -3200,6 +3200,63 @@ "react": ">=16.x" } }, + "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz", + "integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz", + "integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.1.tgz", + "integrity": "sha512-093l7DAkx0aEtBq66Sf19MgoZewv1zeY9/4C7vSKPO4qMwEsW/2VYTUTpBtLwfb9T2R73tXaRDPmE4UqLCYHfg==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.1.tgz", + "integrity": "sha512-m6ShXn+wvqEU69wSP84coxLbNl7sGVZb+Ca+XZq6k30SzuP3X4TfPqtycgUh9ASwlNh5OfQCd8pDIWxl+O+LlQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz", + "integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/react-fontawesome": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", diff --git a/package.json b/package.json index a734a8266..c45540c90 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "dependencies": { "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", - "@edx/frontend-component-footer": "12.6.0", + "@edx/frontend-component-footer": "12.6.1", "@edx/frontend-component-header": "4.10.1", "@edx/frontend-platform": "5.6.1", "@edx/paragon": "20.46.3", From e5a21f4a75bd81564d05bb4411e83edb83798242 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:16:54 +0500 Subject: [PATCH 12/18] chore(deps): update dependency @edx/frontend-build to v13.0.12 (#624) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 854 +++++++++++++++++++++++++++------------------- package.json | 2 +- 2 files changed, 502 insertions(+), 354 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5fb6da815..01ae21185 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@edx/browserslist-config": "1.2.0", - "@edx/frontend-build": "13.0.8", + "@edx/frontend-build": "13.0.12", "@edx/reactifex": "1.1.0", "@testing-library/jest-dom": "5.17.0", "@testing-library/react": "12.1.5", @@ -2057,9 +2057,9 @@ } }, "node_modules/@edx/frontend-build": { - "version": "13.0.8", - "resolved": "https://registry.npmjs.org/@edx/frontend-build/-/frontend-build-13.0.8.tgz", - "integrity": "sha512-TXUoF7BTIHe4h+W4Dt9+Gf8PXnfVJRwLKitEkpYUH5r4kDEJfyKKGYSbizkciGI+9QScbhm2u8Alv2agDXV1TA==", + "version": "13.0.12", + "resolved": "https://registry.npmjs.org/@edx/frontend-build/-/frontend-build-13.0.12.tgz", + "integrity": "sha512-YrTTmo98YxN6HevY9KAUcssfCAFzHlSqwN+8y5fb3hWoCfBX5XapZdpjP3Uawet0/ESIxV6HFQLJ8N21xVXVsg==", "dependencies": { "@babel/cli": "7.22.5", "@babel/core": "7.22.5", @@ -2095,12 +2095,12 @@ "eslint-plugin-react-hooks": "4.6.0", "express": "4.18.2", "file-loader": "6.2.0", - "html-webpack-plugin": "5.5.3", + "html-webpack-plugin": "5.5.4", "identity-obj-proxy": "3.0.0", "image-minimizer-webpack-plugin": "3.8.3", "jest": "26.6.3", "mini-css-extract-plugin": "1.6.2", - "postcss": "8.4.31", + "postcss": "8.4.32", "postcss-custom-media": "10.0.2", "postcss-loader": "7.3.3", "postcss-rtlcss": "4.0.9", @@ -2109,12 +2109,12 @@ "resolve-url-loader": "5.0.0", "sass": "1.69.5", "sass-loader": "13.3.2", - "sharp": "0.32.6", + "sharp": "0.33.0", "source-map-loader": "4.0.1", "style-loader": "3.3.3", "url-loader": "4.1.1", "webpack": "5.89.0", - "webpack-bundle-analyzer": "4.9.1", + "webpack-bundle-analyzer": "4.10.1", "webpack-cli": "5.1.4", "webpack-dev-server": "4.15.1", "webpack-merge": "5.9.0" @@ -3864,6 +3864,21 @@ "node": ">=12" } }, + "node_modules/@emnapi/runtime": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.44.0.tgz", + "integrity": "sha512-ZX/etZEZw8DR7zAB1eVQT40lNo0jeqpb6dCgOvctB6FIQ5PoXfMuNY8+ayQfu8tNQbAB8gQWSSJupR8NxeiZXw==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "optional": true + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -4317,6 +4332,437 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.0.tgz", + "integrity": "sha512-070tEheekI1LJWTGPC9WlQEa5UoKTXzzlORBHMX4TbfUxMiL336YHR8vBEUNsjse0RJCX8dZ4ZXwT595aEF1ug==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.0" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.0.tgz", + "integrity": "sha512-pu/nvn152F3qbPeUkr+4e9zVvEhD3jhwzF473veQfMPkOYo9aoWXSfdZH/E6F+nYC3qvFjbxbvdDbUtEbghLqw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.0.tgz", + "integrity": "sha512-VzYd6OwnUR81sInf3alj1wiokY50DjsHz5bvfnsFpxs5tqQxESoHtJO6xyksDs3RIkyhMWq2FufXo6GNSU9BMw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=11", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.0.tgz", + "integrity": "sha512-dD9OznTlHD6aovRswaPNEy8dKtSAmNo4++tO7uuR4o5VxbVAOoEQ1uSmN4iFAdQneTHws1lkTZeiXPrcCkh6IA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=10.13", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.0.tgz", + "integrity": "sha512-VwgD2eEikDJUk09Mn9Dzi1OW2OJFRQK+XlBTkUNmAWPrtj8Ly0yq05DFgu1VCMx2/DqCGQVi5A1dM9hTmxf3uw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.0.tgz", + "integrity": "sha512-xTYThiqEZEZc0PRU90yVtM3KE7lw1bKdnDQ9kCTHWbqWyHOe4NpPOtMGy27YnN51q0J5dqRrvicfPbALIOeAZA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.0.tgz", + "integrity": "sha512-o9E46WWBC6JsBlwU4QyU9578G77HBDT1NInd+aERfxeOPbk0qBZHgoDsQmA2v9TbqJRWzoBPx1aLOhprBMgPjw==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.0.tgz", + "integrity": "sha512-naldaJy4hSVhWBgEjfdBY85CAa4UO+W1nx6a1sWStHZ7EUfNiuBTTN2KUYT5dH1+p/xij1t2QSXfCiFJoC5S/Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.0.tgz", + "integrity": "sha512-OdorplCyvmSAPsoJLldtLh3nLxRrkAAAOHsGWGDYfN0kh730gifK+UZb3dWORRa6EusNqCTjfXV4GxvgJ/nPDQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.0.tgz", + "integrity": "sha512-FW8iK6rJrg+X2jKD0Ajhjv6y74lToIBEvkZhl42nZt563FfxkCYacrXZtd+q/sRQDypQLzY5WdLkVTbJoPyqNg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.0.tgz", + "integrity": "sha512-4horD3wMFd5a0ddbDY8/dXU9CaOgHjEHALAddXgafoR5oWq5s8X61PDgsSeh4Qupsdo6ycfPPSSNBrfVQnwwrg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.0" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.0.tgz", + "integrity": "sha512-dcomVSrtgF70SyOr8RCOCQ8XGVThXwe71A1d8MGA+mXEVRJ/J6/TrCbBEJh9ddcEIIsrnrkolaEvYSHqVhswQw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.0" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.0.tgz", + "integrity": "sha512-TiVJbx38J2rNVfA309ffSOB+3/7wOsZYQEOlKqOUdWD/nqkjNGrX+YQGz7nzcf5oy2lC+d37+w183iNXRZNngQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.0" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.0.tgz", + "integrity": "sha512-PaZM4Zi7/Ek71WgTdvR+KzTZpBqrQOFcPe7/8ZoPRlTYYRe43k6TWsf4GVH6XKRLMYeSp8J89RfAhBrSP4itNA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.0" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.0.tgz", + "integrity": "sha512-1QLbbN0zt+32eVrg7bb1lwtvEaZwlhEsY1OrijroMkwAqlHqFj6R33Y47s2XUv7P6Ie1PwCxK/uFnNqMnkd5kg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.0" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.0.tgz", + "integrity": "sha512-CecqgB/CnkvCWFhmfN9ZhPGMLXaEBXl4o7WtA6U3Ztrlh/s7FUKX4vNxpMSYLIrWuuzjiaYdfU3+Tdqh1xaHfw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.0" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.0.tgz", + "integrity": "sha512-Hn4js32gUX9qkISlemZBUPuMs0k/xNJebUNl/L6djnU07B/HAA2KaxRVb3HvbU5fL242hLOcp0+tR+M8dvJUFw==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/runtime": "^0.44.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.0.tgz", + "integrity": "sha512-5HfcsCZi3l5nPRF2q3bllMVMDXBqEWI3Q8KQONfzl0TferFE5lnsIG0A1YrntMAGqvkzdW6y1Ci1A2uTvxhfzg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.0.tgz", + "integrity": "sha512-i3DtP/2ce1yKFj4OzOnOYltOEL/+dp4dc4dJXJBv6god1AFTcmkaA99H/7SwOmkCOBQkbVvA3lCGm3/5nDtf9Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -7853,11 +8299,6 @@ "deep-equal": "^2.0.5" } }, - "node_modules/b4a": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", - "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==" - }, "node_modules/babel-jest": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", @@ -8813,11 +9254,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -9656,6 +10092,11 @@ "node": ">=10" } }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -9693,20 +10134,6 @@ "node": ">=0.10" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -9746,14 +10173,6 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -11377,14 +11796,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "engines": { - "node": ">=6" - } - }, "node_modules/expect": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", @@ -11669,11 +12080,6 @@ "resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.7.tgz", "integrity": "sha512-tJ01ulDWT2WhqxMKS20nXX6wyX2iInBYpbN3GO7yjKwXMY4qvkdBRxak9IFwBLlFDESox+SwSvqMCZDfe1tqeg==" }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" - }, "node_modules/fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -12330,11 +12736,6 @@ "node": ">= 0.6" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -12487,11 +12888,6 @@ "node": ">=0.10.0" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -12900,9 +13296,9 @@ } }, "node_modules/html-webpack-plugin": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", - "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.4.tgz", + "integrity": "sha512-3wNSaVVxdxcu0jd4FpQFoICdqgxs4zIQQvj+2yQKFfBOnLETQ6X5CDWdeasuGlSsooFlMkEioWDTqBv1wvw5Iw==", "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", @@ -17796,21 +18192,6 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, - "node_modules/lodash.escape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", - "integrity": "sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==" - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" - }, - "node_modules/lodash.invokemap": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz", - "integrity": "sha512-CfkycNtMqgUlfjfdh2BhKO/ZXrP8ePOX5lEU/g0R3ItJcnuxWDwokMGKx1hWcfOikmyOVx6X9IwWnDGlgKl61w==" - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -17821,11 +18202,6 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.pullall": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.pullall/-/lodash.pullall-4.2.0.tgz", - "integrity": "sha512-VhqxBKH0ZxPpLhiu68YD1KnHmbhQJQctcipvmFnqIBDYzcIHzf3Zpu0tpeOKtR4x76p9yohc506eGdOjTmyIBg==" - }, "node_modules/lodash.snakecase": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", @@ -18130,17 +18506,6 @@ "node": ">=6" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -18206,11 +18571,6 @@ "node": ">=0.10.0" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, "node_modules/mrmime": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", @@ -18242,9 +18602,9 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -18279,11 +18639,6 @@ "node": ">=0.10.0" } }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -18321,52 +18676,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "node_modules/node-abi": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.47.0.tgz", - "integrity": "sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A==", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/node-addon-api": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", - "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" - }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -19301,9 +19610,9 @@ } }, "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "funding": [ { "type": "opencollective", @@ -19319,7 +19628,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -19926,70 +20235,6 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, - "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prebuild-install/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prebuild-install/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/prebuild-install/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -20239,11 +20484,6 @@ } ] }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -20293,28 +20533,6 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", @@ -21966,25 +22184,42 @@ "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" }, "node_modules/sharp": { - "version": "0.32.6", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", - "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.0.tgz", + "integrity": "sha512-99DZKudjm/Rmz+M0/26t4DKpXyywAOJaayGS9boEn7FvgtG0RYBi46uPE2c+obcJRtA3AZa0QwJot63gJQ1F0Q==", "hasInstallScript": true, "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.2", - "node-addon-api": "^6.1.0", - "prebuild-install": "^7.1.1", - "semver": "^7.5.4", - "simple-get": "^4.0.1", - "tar-fs": "^3.0.4", - "tunnel-agent": "^0.6.0" + "semver": "^7.5.4" }, "engines": { - "node": ">=14.15.0" + "libvips": ">=8.15.0", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.0", + "@img/sharp-darwin-x64": "0.33.0", + "@img/sharp-libvips-darwin-arm64": "1.0.0", + "@img/sharp-libvips-darwin-x64": "1.0.0", + "@img/sharp-libvips-linux-arm": "1.0.0", + "@img/sharp-libvips-linux-arm64": "1.0.0", + "@img/sharp-libvips-linux-s390x": "1.0.0", + "@img/sharp-libvips-linux-x64": "1.0.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.0", + "@img/sharp-libvips-linuxmusl-x64": "1.0.0", + "@img/sharp-linux-arm": "0.33.0", + "@img/sharp-linux-arm64": "0.33.0", + "@img/sharp-linux-s390x": "0.33.0", + "@img/sharp-linux-x64": "0.33.0", + "@img/sharp-linuxmusl-arm64": "0.33.0", + "@img/sharp-linuxmusl-x64": "0.33.0", + "@img/sharp-wasm32": "0.33.0", + "@img/sharp-win32-ia32": "0.33.0", + "@img/sharp-win32-x64": "0.33.0" } }, "node_modules/sharp/node_modules/lru-cache": { @@ -22068,49 +22303,6 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -22681,15 +22873,6 @@ "node": ">= 0.4" } }, - "node_modules/streamx": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz", - "integrity": "sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==", - "dependencies": { - "fast-fifo": "^1.1.0", - "queue-tick": "^1.0.1" - } - }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -23080,26 +23263,6 @@ "node": ">=6" } }, - "node_modules/tar-fs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", - "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", - "dependencies": { - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - } - }, - "node_modules/tar-stream": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", - "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, "node_modules/terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -23388,17 +23551,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -23942,23 +24094,19 @@ } }, "node_modules/webpack-bundle-analyzer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.1.tgz", - "integrity": "sha512-jnd6EoYrf9yMxCyYDPj8eutJvtjQNp8PHmni/e/ulydHBWhT5J3menXt3HEkScsu9YqMAcG4CfFjs3rj5pVU1w==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", + "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", "dependencies": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", "acorn-walk": "^8.0.0", "commander": "^7.2.0", + "debounce": "^1.2.1", "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", "is-plain-object": "^5.0.0", - "lodash.debounce": "^4.0.8", - "lodash.escape": "^4.0.1", - "lodash.flatten": "^4.4.0", - "lodash.invokemap": "^4.6.0", - "lodash.pullall": "^4.2.0", - "lodash.uniqby": "^4.7.0", "opener": "^1.5.2", "picocolors": "^1.0.0", "sirv": "^2.0.3", diff --git a/package.json b/package.json index c45540c90..44fc76666 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ }, "devDependencies": { "@edx/browserslist-config": "1.2.0", - "@edx/frontend-build": "13.0.8", + "@edx/frontend-build": "13.0.12", "@edx/reactifex": "1.1.0", "@testing-library/jest-dom": "5.17.0", "@testing-library/react": "12.1.5", From 9761787c89f60e2c5b250ab43d6dcb5e1cb84a8b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 12:30:12 +0500 Subject: [PATCH 13/18] fix(deps): update dependency @reduxjs/toolkit to v1.9.7 (#616) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 20 ++++++++++---------- package.json | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 01ae21185..58244f38e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@edx/frontend-component-header": "4.10.1", "@edx/frontend-platform": "5.6.1", "@edx/paragon": "20.46.3", - "@reduxjs/toolkit": "1.8.0", + "@reduxjs/toolkit": "1.9.7", "@tinymce/tinymce-react": "3.13.1", "babel-polyfill": "6.26.0", "classnames": "2.3.2", @@ -6515,18 +6515,18 @@ } }, "node_modules/@reduxjs/toolkit": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.0.tgz", - "integrity": "sha512-cdfHWfcvLyhBUDicoFwG1u32JqvwKDxLxDd7zSmSoFw/RhYLOygIRtmaMjPRUUHmVmmAGAvquLLsKKU/677kSQ==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", + "integrity": "sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==", "dependencies": { - "immer": "^9.0.7", - "redux": "^4.1.2", - "redux-thunk": "^2.4.1", - "reselect": "^4.1.5" + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" }, "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || 18.0.0-beta", - "react-redux": "^7.2.1 || ^8.0.0-beta" + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" }, "peerDependenciesMeta": { "react": { diff --git a/package.json b/package.json index 44fc76666..f646a2556 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "@edx/frontend-component-header": "4.10.1", "@edx/frontend-platform": "5.6.1", "@edx/paragon": "20.46.3", - "@reduxjs/toolkit": "1.8.0", + "@reduxjs/toolkit": "1.9.7", "@tinymce/tinymce-react": "3.13.1", "babel-polyfill": "6.26.0", "classnames": "2.3.2", From f31a0e71f3346a9284033f6ef0992fcacff9ce42 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 15:15:42 +0500 Subject: [PATCH 14/18] fix(deps): update dependency formik to v2.4.5 (#619) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 16 +++++++++++----- package.json | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 58244f38e..127aafce2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "classnames": "2.3.2", "core-js": "3.21.1", "dompurify": "^2.4.3", - "formik": "2.2.9", + "formik": "2.4.5", "lodash.snakecase": "4.1.1", "prop-types": "15.8.1", "raw-loader": "4.0.2", @@ -12667,9 +12667,9 @@ } }, "node_modules/formik": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz", - "integrity": "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.5.tgz", + "integrity": "sha512-Gxlht0TD3vVdzMDHwkiNZqJ7Mvg77xQNfmBRrNtvzcHZs72TJppSTDKHpImCMJZwcWPBJ8jSQQ95GJzXFf1nAQ==", "funding": [ { "type": "individual", @@ -12677,13 +12677,14 @@ } ], "dependencies": { + "@types/hoist-non-react-statics": "^3.3.1", "deepmerge": "^2.1.1", "hoist-non-react-statics": "^3.3.0", "lodash": "^4.17.21", "lodash-es": "^4.17.21", "react-fast-compare": "^2.0.1", "tiny-warning": "^1.0.2", - "tslib": "^1.10.0" + "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0" @@ -12697,6 +12698,11 @@ "node": ">=0.10.0" } }, + "node_modules/formik/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", diff --git a/package.json b/package.json index f646a2556..e597338fe 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "classnames": "2.3.2", "core-js": "3.21.1", "dompurify": "^2.4.3", - "formik": "2.2.9", + "formik": "2.4.5", "lodash.snakecase": "4.1.1", "prop-types": "15.8.1", "raw-loader": "4.0.2", From 67d79cb3aadf17c226ac5758959bc67c7784df07 Mon Sep 17 00:00:00 2001 From: Jenkins Date: Sun, 17 Dec 2023 20:17:07 +0000 Subject: [PATCH 15/18] chore(i18n): update translations --- src/i18n/messages/hi.json | 400 +++++++++++++++++++------------------- 1 file changed, 200 insertions(+), 200 deletions(-) diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index c9fbbe994..ed5a83b10 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -1,211 +1,211 @@ { - "discussions.actions.button.alt": "Actions menu", - "discussions.actions.copylink": "Copy link", - "discussions.actions.edit": "Edit", - "discussions.actions.pin": "Pin", - "discussions.actions.unpin": "Unpin", - "discussions.actions.delete": "Delete", - "discussions.confirmation.button.confirm": "Confirm", - "discussions.actions.close": "Close", - "discussions.actions.reopen": "Reopen", - "discussions.actions.report": "Report", - "discussions.actions.unreport": "Unreport", - "discussions.actions.endorse": "Endorse", - "discussions.actions.unendorse": "Unendorse", - "discussions.actions.markAnswered": "Mark as answered", - "discussions.actions.unMarkAnswered": "Unmark as answered", - "discussions.modal.confirmation.button.cancel": "Cancel", - "discussions.empty.allTopics": "All discussion activity for these topics will show up here.", - "discussions.empty.allPosts": "All discussion activity for your course will show up here.", - "discussions.empty.myPosts": "Posts you've interacted with will show up here.", - "discussions.empty.topic": "All discussion activity for this topic will show up here.", - "discussions.empty.title": "Nothing here yet", - "discussions.empty.noPostSelected": "No post selected", - "discussions.empty.noTopicSelected": "No topic selected", - "discussions.sidebar.noResultsFound": "No results found", - "discussions.sidebar.differentKeywords": "Try searching different keywords", - "discussions.sidebar.removeKeywords": "Try searching different keywords or removing some filters", - "discussions.sidebar.removeKeywordsOnly": "Try searching different keywords", - "discussions.sidebar.removeFilters": "Try removing some filters", - "discussions.empty.iconAlt": "Empty", - "discussions.authors.label.staff": "Staff", - "discussions.authors.label.ta": "TA", - "discussions.learner.loadMostPosts": "Load more posts", - "discussions.post.anonymous.author": "anonymous", - "discussion.blackoutBanner.information": "Posting in discussions is disabled by the course team", - "discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions", - "discussions.editor.image.warning.title": "Warning!", - "discussions.editor.image.warning.dismiss": "Ok", - "navigation.course.tabs.label": "Course Material", - "discussions.topics.backAlt": "Back to topics list", + "discussions.actions.button.alt": "एक्शन मेन्यू", + "discussions.actions.copylink": "कॉपी लिंक", + "discussions.actions.edit": "संपादित करें", + "discussions.actions.pin": "पिन", + "discussions.actions.unpin": "अनपिन", + "discussions.actions.delete": "नष्ट करें", + "discussions.confirmation.button.confirm": "पुष्टि करें", + "discussions.actions.close": "बंद करे", + "discussions.actions.reopen": "फिर से खोलें", + "discussions.actions.report": "रिपोर्ट", + "discussions.actions.unreport": "अनरिपोर्ट", + "discussions.actions.endorse": "समर्थन", + "discussions.actions.unendorse": "समर्थन न करें", + "discussions.actions.markAnswered": "उत्तर के रूप में चिह्नित करें", + "discussions.actions.unMarkAnswered": "उत्तर के रूप में अचिह्नित करें", + "discussions.modal.confirmation.button.cancel": "रद्द करना", + "discussions.empty.allTopics": "इन विषयों के लिए सभी चर्चा गतिविधियाँ यहाँ दिखाई देंगी।", + "discussions.empty.allPosts": "आपके पाठ्यक्रम की सभी चर्चा गतिविधियाँ यहाँ दिखाई देंगी।", + "discussions.empty.myPosts": "जिन पोस्टों के साथ आपने इंटरैक्ट किया है वे यहां दिखाई देंगी।", + "discussions.empty.topic": "इस विषय की सभी चर्चा गतिविधियाँ यहाँ दिखाई देंगी।", + "discussions.empty.title": "अभी तक यहां कुछ भी नहीं है", + "discussions.empty.noPostSelected": "कोई पोस्ट चयनित नहीं", + "discussions.empty.noTopicSelected": "कोई विषय चयनित नहीं", + "discussions.sidebar.noResultsFound": "कोई परिणाम नहीं मिला", + "discussions.sidebar.differentKeywords": "अलग-अलग कीवर्ड खोजने का प्रयास करें", + "discussions.sidebar.removeKeywords": "अलग-अलग कीवर्ड खोजने या कुछ फ़िल्टर हटाने का प्रयास करें", + "discussions.sidebar.removeKeywordsOnly": "अलग-अलग कीवर्ड खोजने का प्रयास करें", + "discussions.sidebar.removeFilters": "कुछ फ़िल्टर हटाने का प्रयास करें", + "discussions.empty.iconAlt": "खाली", + "discussions.authors.label.staff": "कर्मचारी", + "discussions.authors.label.ta": "टीए", + "discussions.learner.loadMostPosts": "और पोस्ट लोड करें", + "discussions.post.anonymous.author": "गुमनाम", + "discussion.blackoutBanner.information": "चर्चाओं में पोस्ट करना पाठ्यक्रम टीम द्वारा अक्षम कर दिया गया है", + "discussions.editor.image.warning.message": "जब पोस्ट, प्रतिक्रिया या टिप्पणी को इन-लाइन पाठ्यक्रम चर्चाओं का उपयोग करके देखा जाता है तो 999px से अधिक चौड़ाई या ऊंचाई वाली छवियां दिखाई नहीं देंगी", + "discussions.editor.image.warning.title": "चेतावनी!", + "discussions.editor.image.warning.dismiss": "ठीक", + "navigation.course.tabs.label": "पाठ्यक्रम सामग्री", + "discussions.topics.backAlt": "विषय सूची पर वापस जाएं", "discussions.topics.discussions": "{count, plural, =0 {Discussion} one {# Discussion} other {# Discussions} }", "discussions.topics.questions": "{count, plural, =0 {Question} one {# Question} other {# Questions} }", - "discussions.topics.reported": "{reported} reported", - "discussions.topics.previouslyReported": "{previouslyReported} previously reported", - "discussions.topics.find.label": "Search topics", - "discussions.topics.unnamed.section.label": "Unnamed Section", - "discussions.topics.unnamed.subsection.label": "Unnamed Subsection", - "discussions.subtopics.unnamed.topic.label": "Unnamed Topic", - "discussions.topics.title": "No topic exists", - "discussions.topics.createTopic": "Please contact you admin to create a topic", - "discussions.topics.nothing": "Nothing here yet", - "discussions.topics.archived.label": "Archived", - "discussions.learner.reported": "{reported} reported", - "discussions.learner.previouslyReported": "{previouslyReported} previously reported", - "discussions.learner.lastLogin": "Last active {lastActiveTime}", - "discussions.learner.loadMostLearners": "Load more", - "discussions.learner.back": "Back", - "discussions.learner.activityForLearner": "Activity for {username}", - "discussions.learner.mostActivity": "Most activity", - "discussions.learner.reportedActivity": "Reported activity", - "discussions.learner.recentActivity": "Recent activity", - "discussions.learner.sortFilterStatus": "All learners sorted by {sort, select, flagged {reported activity} activity {most activity} other {{sort}} }", - "discussion.learner.allActivity": "All activity", - "discussion.learner.posts": "Posts", - "discussions.comments.comment.addComment": "Add comment", - "discussions.comments.comment.addResponse": "Add a response", - "discussions.comments.comment.abuseFlaggedMessage": "Content reported for staff to review", - "discussions.actions.back.alt": "Back to list", + "discussions.topics.reported": "{reported} रिपोर्ट किया गया", + "discussions.topics.previouslyReported": "{previouslyReported} ने पहले रिपोर्ट किया था", + "discussions.topics.find.label": "विषय खोजें", + "discussions.topics.unnamed.section.label": "अनाम अनुभाग", + "discussions.topics.unnamed.subsection.label": "अनाम उपखंड", + "discussions.subtopics.unnamed.topic.label": "अनाम विषय", + "discussions.topics.title": "कोई विषय मौजूद नहीं है", + "discussions.topics.createTopic": "विषय बनाने के लिए कृपया अपने व्यवस्थापक से संपर्क करें", + "discussions.topics.nothing": "अभी तक यहां कुछ भी नहीं है", + "discussions.topics.archived.label": "संग्रहीत", + "discussions.learner.reported": "{reported} रिपोर्ट किया गया", + "discussions.learner.previouslyReported": "{previouslyReported} ने पहले रिपोर्ट किया था", + "discussions.learner.lastLogin": "अंतिम सक्रिय {lastActiveTime}", + "discussions.learner.loadMostLearners": "और लोड करें", + "discussions.learner.back": "वापस", + "discussions.learner.activityForLearner": "{username} के लिए गतिविधि", + "discussions.learner.mostActivity": "सर्वाधिक गतिविधि", + "discussions.learner.reportedActivity": "रिपोर्ट की गई गतिविधि", + "discussions.learner.recentActivity": "हाल की गतिविधि", + "discussions.learner.sortFilterStatus": "सभी शिक्षार्थियों को {sort, select, flagged {reported activity} activity {most activity} other {{sort}} }", + "discussion.learner.allActivity": "सारी गतिविधि", + "discussion.learner.posts": "पोस्ट", + "discussions.comments.comment.addComment": "टिप्पणी जोड़ें", + "discussions.comments.comment.addResponse": "एक प्रतिक्रिया जोड़ें", + "discussions.comments.comment.abuseFlaggedMessage": "कर्मचारियों की समीक्षा के लिए सामग्री रिपोर्ट की गई", + "discussions.actions.back.alt": "सूची पर वापस जाएं", "discussions.comments.comment.responseCount": "{num, plural, =0 {No responses} one {Showing # response} other {Showing # responses} }", "discussions.comments.comment.endorsedResponseCount": "{num, plural, =0 {No endorsed responses} one {Showing # endorsed response} other {Showing # endorsed responses} }", - "discussions.comments.comment.loadMoreComments": "Load more comments", - "discussions.comments.comment.loadMoreResponses": "Load more responses", - "discussions.comments.comment.visibility": "This post is visible to {group, select, null {Everyone} other {{group}} }.", + "discussions.comments.comment.loadMoreComments": "और टिप्पणियों को लोड करें", + "discussions.comments.comment.loadMoreResponses": "अधिक प्रतिक्रियाएं लोड करें", + "discussions.comments.comment.visibility": "यह पोस्ट {group, select, null {Everyone} other {{group}} } को दृश्यमान है।", "discussions.comments.comment.postedTime": "{postType, select, discussion {Discussion} question {Question} other {{postType}} } posted {relativeTime} by", - "discussions.comments.comment.commentTime": "Posted {relativeTime}", - "discussions.comments.comment.answer": "Answer", - "discussions.comments.comment.answeredlabel": "Marked as answered by", - "discussions.comments.comment.endorsed": "Endorsed", - "discussions.comments.comment.endorsedlabel": "Endorsed by", - "discussions.actions.label": "Actions menu", - "discussions.editor.submit": "Submit", - "discussions.editor.submitting": "Submitting", - "discussions.editor.cancel": "Cancel", - "discussions.editor.error.empty": "Post content cannot be empty.", - "discussions.editor.delete.response.title": "Delete response", - "discussions.editor.delete.response.description": "Are you sure you want to permanently delete this response?", - "discussions.editor.delete.comment.title": "Delete comment", - "discussions.editor.delete.comment.description": "Are you sure you want to permanently delete this comment?", - "discussions.delete.confirmation.button.delete": "Delete", - "discussions.editor.response.response.title": "Report inappropriate content?", - "discussions.editor.response.description": "The discussion moderation team will review this content and take appropriate action.", - "discussions.editor.report.comment.title": "Report inappropriate content?", - "discussions.editor.report.comment.description": "The discussion moderation team will review this content and take appropriate action.", - "discussions.editor.comments.editReasonCode": "Reason for editing", - "discussions.editor.posts.editReasonCode.error": "Select reason for editing", - "discussions.comment.comments.editedBy": "Edited by", + "discussions.comments.comment.commentTime": "{relativeTime} पोस्ट किया गया", + "discussions.comments.comment.answer": "उत्तर", + "discussions.comments.comment.answeredlabel": "उत्तर देने के रूप में चिह्नित किया गया", + "discussions.comments.comment.endorsed": "समर्थन किया", + "discussions.comments.comment.endorsedlabel": "द्वारा समर्थन", + "discussions.actions.label": "एक्शन मेन्यू", + "discussions.editor.submit": "प्रस्तुत", + "discussions.editor.submitting": "भेजने से", + "discussions.editor.cancel": "रद्द करना", + "discussions.editor.error.empty": "पोस्ट सामग्री खाली नहीं हो सकती।", + "discussions.editor.delete.response.title": "प्रतिक्रिया हटाएँ", + "discussions.editor.delete.response.description": "क्या आप वाकई इस प्रतिक्रिया को स्थायी रूप से हटाना चाहते हैं?", + "discussions.editor.delete.comment.title": "टिप्पणी हटाएँ", + "discussions.editor.delete.comment.description": "क्या आप वाकई इस टिप्पणी को स्थायी रूप से हटाना चाहते हैं?", + "discussions.delete.confirmation.button.delete": "नष्ट करें", + "discussions.editor.response.response.title": "अनुचित सामग्री की रिपोर्ट करें?", + "discussions.editor.response.description": "चर्चा मॉडरेशन टीम इस सामग्री की समीक्षा करेगी और उचित कार्रवाई करेगी।", + "discussions.editor.report.comment.title": "अनुचित सामग्री की रिपोर्ट करें?", + "discussions.editor.report.comment.description": "चर्चा मॉडरेशन टीम इस सामग्री की समीक्षा करेगी और उचित कार्रवाई करेगी।", + "discussions.editor.comments.editReasonCode": "संपादन का कारण", + "discussions.editor.posts.editReasonCode.error": "संपादन का कारण चुनें", + "discussions.comment.comments.editedBy": "द्वारा संपादित", "discussions.comment.comments.fullStop": "•", - "discussions.comment.comments.reason": "Reason", - "discussions.post.closedBy": "Post closed by", - "discussion.comment.time": "{time} ago", - "discussion.thread.notFound": "Thread not found", + "discussions.comment.comments.reason": "कारण", + "discussions.post.closedBy": "पोस्ट बंद कर दी गई", + "discussion.comment.time": "{time} पहले", + "discussion.thread.notFound": "थ्रेड नहीं मिला", "discussions.comment.sortFilterStatus": "{sort, select, false {Oldest first} true {Newest first} other {{sort}} }", - "discussions.topics.sort.message": "Sorted by {sortBy}", - "discussions.topics.sort.lastActivity": "Recent activity", - "discussions.topics.sort.commentCount": "Most activity", - "discussions.topics.sort.courseStructure": "Course Structure", - "discussions.topics.unnamed.label": "Unnamed category", - "discussions.subtopics.unnamed.label": "Unnamed subcategory", - "tour.action.advance": "Next", - "tour.action.dismiss": "Dismiss", - "tour.action.end": "Okay", - "tour.body.notRespondedFilter": "Now you can filter discussions to find posts with no response.", - "tour.title.notRespondedFilter": "New filtering option!", - "tour.body.responseSortTour": "Responses and comments are now sorted by newest first. Please use this option to change the sort order", - "tour.title.responseSortTour": "Sort Responses!", - "learn.course.tabs.navigation.overflow.menu": "More...", - "discussions.navigation.breadcrumbMenu.allTopics": "Topics", - "discussions.navigation.breadcrumbMenu.showAll": "Show all", - "discussions.navigation.navigationBar.allPosts": "All posts", - "discussions.navigation.navigationBar.allTopics": "Topics", - "discussions.navigation.navigationBar.myPosts": "My posts", - "discussions.navigation.navigationBar.learners": "Learners", - "discussions.post.author.anonymous": "anonymous", - "discussions.post.addResponse": "Add response", - "discussions.post.lastResponse": "Last response {time}", - "discussions.post.postedOn": "Posted {time} by {author} {authorLabel}", - "discussions.post.contentReported": "Reported", - "discussions.post.following": "Following", - "discussions.post.follow": "Follow", - "discussions.post.followed": "Followed", - "discussions.post.notFollowed": "Not Followed", - "discussions.post.answered": "Answered", - "discussions.post.unFollow": "Unfollow", - "discussions.post.like": "Like", - "discussions.post.removeLike": "Unlike", - "discussions.post.liked": "liked", - "discussions.post.likes": "likes", - "discussions.post.viewActivity": "View activity", - "discussions.post.activity": "Activity", - "discussions.post.closed": "Post closed for responses and comments", - "discussions.post.relatedTo": "Related to", - "discussions.editor.delete.post.title": "Delete post", - "discussions.editor.delete.post.description": "Are you sure you want to permanently delete this post?", - "discussions.post.delete.confirmation.button.delete": "Delete", - "discussions.editor.report.post.title": "Report inappropriate content?", - "discussions.editor.report.post.description": "The discussion moderation team will review this content and take appropriate action.", - "discussions.post.closePostModal.title": "Close post", - "discussions.post.closePostModal.text": "Enter a reason for closing this post. This will only be displayed to other moderators.", - "discussions.post.closePostModal.reasonCodeInput": "Reason", - "discussions.post.closePostModal.cancel": "Cancel", - "discussions.post.closePostModal.confirm": "Close post", - "discussions.post.label.new": "{count} New", - "discussions.post.editedBy": "Edited by", - "discussions.post.editReason": "Reason", - "discussions.post.postWithoutPreview": "No preview available", - "discussions.post.follow.description": "you are following this post", - "discussions.post.unfollow.description": "you are not following this post", - "discussions.app.title": "Discussions", - "discussions.posts.actionBar.searchAllPosts": "Search all posts", + "discussions.topics.sort.message": "{sortBy} द्वारा क्रमबद्ध", + "discussions.topics.sort.lastActivity": "हाल की गतिविधि", + "discussions.topics.sort.commentCount": "सर्वाधिक गतिविधि", + "discussions.topics.sort.courseStructure": "पाठ्यक्रम संरचना", + "discussions.topics.unnamed.label": "अनाम श्रेणी", + "discussions.subtopics.unnamed.label": "अनाम उपश्रेणी", + "tour.action.advance": "अगला", + "tour.action.dismiss": "ख़ारिज करें", + "tour.action.end": "ठीक है", + "tour.body.notRespondedFilter": "अब आप बिना प्रतिक्रिया वाली पोस्ट ढूंढने के लिए चर्चाओं को फ़िल्टर कर सकते हैं।", + "tour.title.notRespondedFilter": "नया फ़िल्टरिंग विकल्प!", + "tour.body.responseSortTour": "प्रतिक्रियाएँ और टिप्पणियाँ अब सबसे पहले नवीनतम के अनुसार क्रमबद्ध की जाती हैं। कृपया क्रम बदलने के लिए इस विकल्प का उपयोग करें", + "tour.title.responseSortTour": "प्रतिक्रियाएँ क्रमबद्ध करें!", + "learn.course.tabs.navigation.overflow.menu": "ज़्यादा...", + "discussions.navigation.breadcrumbMenu.allTopics": "विषय", + "discussions.navigation.breadcrumbMenu.showAll": "सभी दिखाएं", + "discussions.navigation.navigationBar.allPosts": "सभी पोस्ट", + "discussions.navigation.navigationBar.allTopics": "विषय", + "discussions.navigation.navigationBar.myPosts": "मेरी पोस्ट", + "discussions.navigation.navigationBar.learners": "छात्र", + "discussions.post.author.anonymous": "गुमनाम", + "discussions.post.addResponse": "जवाब जोड़ें", + "discussions.post.lastResponse": "अंतिम प्रतिक्रिया {time}", + "discussions.post.postedOn": "{time} {author} {authorLabel} द्वारा पोस्ट", + "discussions.post.contentReported": "सूचित किया जा चूका है", + "discussions.post.following": "फ़ॉलोइंग", + "discussions.post.follow": "फ़ॉलो", + "discussions.post.followed": "अनुसरित", + "discussions.post.notFollowed": "नहीं अनुसरित", + "discussions.post.answered": "उत्‍तरित", + "discussions.post.unFollow": "करें", + "discussions.post.like": "जैसे", + "discussions.post.removeLike": "अलग", + "discussions.post.liked": "पसंद की", + "discussions.post.likes": "पसंद", + "discussions.post.viewActivity": "गतिविधि देखें", + "discussions.post.activity": "पुनः प्रयास करें", + "discussions.post.closed": "प्रतिक्रियाओं और टिप्पणियों के लिए पोस्ट बंद है", + "discussions.post.relatedTo": "संबंधित", + "discussions.editor.delete.post.title": "पोस्ट हटाएं", + "discussions.editor.delete.post.description": "क्या आप वाकई इस पोस्ट को स्थायी रूप से हटाना चाहते हैं?", + "discussions.post.delete.confirmation.button.delete": "नष्ट करें", + "discussions.editor.report.post.title": "अनुचित सामग्री की रिपोर्ट करें?", + "discussions.editor.report.post.description": "चर्चा मॉडरेशन टीम इस सामग्री की समीक्षा करेगी और उचित कार्रवाई करेगी।", + "discussions.post.closePostModal.title": "पोस्ट बंद करें", + "discussions.post.closePostModal.text": "इस पोस्ट को बंद करने का कारण दर्ज करें। यह केवल अन्य मॉडरेटर्स को प्रदर्शित होगा।", + "discussions.post.closePostModal.reasonCodeInput": "कारण", + "discussions.post.closePostModal.cancel": "रद्द करना", + "discussions.post.closePostModal.confirm": "पोस्ट बंद करें", + "discussions.post.label.new": "{count} नया", + "discussions.post.editedBy": "द्वारा संपादित", + "discussions.post.editReason": "कारण", + "discussions.post.postWithoutPreview": "कोई पूर्वावलोकन उपलब्ध नहीं है", + "discussions.post.follow.description": "आप इस पोस्ट का पालन कर रहे हैं", + "discussions.post.unfollow.description": "आप इस पोस्ट का पालन नहीं कर रहे हैं", + "discussions.app.title": "चर्चाएँ", + "discussions.posts.actionBar.searchAllPosts": "सभी पोस्‍ट खोजें", "discussions.posts.actionBar.search": "{page, select, topics {Search topics} posts {Search all posts} learners {Search learners} myPosts {Search all posts} other {{page}} }", - "discussions.actionBar.searchInfo": "Showing {count} results for \"{text}\"", - "discussions.actionBar.searchRewriteInfo": "No results found for \"{searchString}\". Showing {count} results for \"{textSearchRewrite}\".", - "discussions.actionBar.searchInfoSearching": "Searching...", - "discussions.actionBar.clearSearch": "Clear results", - "discussion.posts.actionBar.add": "Add a post", - "discussion.posts.actionBar.close": "Close", - "discussions.post.editor.type": "Post type", - "discussions.post.editor.addPostHeading": "Add a post", - "discussions.post.editor.editPostHeading": "Edit post", - "discussions.post.editor.typeDescription": "Questions raise issues that need answers. Discussions share ideas and start conversations.", - "discussions.post.editor.required": "Required", - "discussions.post.editor.questionType": "Question", - "discussions.post.editor.questionDescription": "Raise issues that need answers", - "discussions.post.editor.discussionType": "Discussion", - "discussions.post.editor.discussionDescription": "Share ideas and start conversations", - "discussions.post.editor.topicArea": "Topic area", - "discussions.post.editor.topicAreaDescription": "Add your post to a relevant topic to help others find it.", - "discussions.post.editor.cohortVisibility": "Cohort visibility", - "discussions.post.editor.cohortVisibilityAllLearners": "All learners", - "discussions.post.editor.title": "Post title", - "discussions.post.editor.titleDescription": "Add a clear and descriptive title to encourage participation.", - "discussions.post.editor.title.error": "Post title cannot be empty.", - "discussions.post.editor.content.error": "Post content cannot be empty.", - "discussions.post.editor.questionText": "Your question or idea (required)", - "discussions.post.editor.preview": "Preview", - "discussions.post.editor.followPost": "Follow this post", - "discussions.post.editor.anonymousPost": "Post anonymously", - "discussions.post.editor.anonymousToPeersPost": "Post anonymously to peers", - "discussions.editor.posts.editReasonCode": "Reason for editing", - "discussions.editor.posts.showPreview.button": "Show preview", - "discussions.topic.noName.label": "Unnamed category", - "discussions.subtopic.noName.label": "Unnamed subcategory", - "discussions.posts.filter.showALl": "Show all", - "discussions.posts.filter.discussions": "Discussions", - "discussions.posts.filter.questions": "Questions", - "discussions.posts.filter.message": "Status: {filterBy}", - "discussions.posts.status.filter.anyStatus": "Any status", - "discussions.posts.status.filter.unread": "Unread", - "discussions.posts.status.filter.following": "Following", - "discussions.posts.status.filter.reported": "Reported", - "discussions.posts.status.filter.unanswered": "Unanswered", - "discussions.posts.status.filter.unresponded": "Not responded", - "discussions.posts.filter.myPosts": "My posts", - "discussions.posts.filter.myDiscussions": "My discussions", - "discussions.posts.filter.myQuestions": "My questions", - "discussions.posts.sort.message": "Sorted by {sortBy}", - "discussions.posts.sort.lastActivity": "Recent activity", - "discussions.posts.sort.commentCount": "Most activity", - "discussions.posts.sort.voteCount": "Most likes", + "discussions.actionBar.searchInfo": "\"{text}\" के लिए {count} परिणाम दिखा रहा है", + "discussions.actionBar.searchRewriteInfo": "\"{searchString}\" के लिए कोई परिणाम नहीं मिले। \"{textSearchRewrite}\" के लिए {count} परिणाम दिखा रहे हैं।", + "discussions.actionBar.searchInfoSearching": "खोज रहा है...", + "discussions.actionBar.clearSearch": "स्पष्ट परिणाम", + "discussion.posts.actionBar.add": "एक पोस्ट जोड़ें", + "discussion.posts.actionBar.close": "बंद करे", + "discussions.post.editor.type": "पद प्रकार", + "discussions.post.editor.addPostHeading": "एक पोस्ट जोड़ें", + "discussions.post.editor.editPostHeading": "संपादित पोस्ट", + "discussions.post.editor.typeDescription": "प्रश्न ऐसे मुद्दे उठाते हैं जिनके उत्तर की आवश्यकता होती है। चर्चाएँ विचार साझा करती हैं और बातचीत शुरू करती हैं।", + "discussions.post.editor.required": "आवश्यक", + "discussions.post.editor.questionType": "सवाल", + "discussions.post.editor.questionDescription": "जवाब दें", + "discussions.post.editor.discussionType": "चर्चा", + "discussions.post.editor.discussionDescription": "विचारों को साझा करें और बातचीत शुरू करें", + "discussions.post.editor.topicArea": "विषय क्षेत्र", + "discussions.post.editor.topicAreaDescription": "दूसरों को इसे ढूंढने में मदद करने के लिए अपनी पोस्ट को किसी प्रासंगिक विषय पर जोड़ें।", + "discussions.post.editor.cohortVisibility": "समूह दृश्यता", + "discussions.post.editor.cohortVisibilityAllLearners": "सभी शिक्षार्थी", + "discussions.post.editor.title": "पोस्ट शीर्षक", + "discussions.post.editor.titleDescription": "भागीदारी को प्रोत्साहित करने के लिए एक स्पष्ट और वर्णनात्मक शीर्षक जोड़ें।", + "discussions.post.editor.title.error": "पोस्ट शीर्षक खाली नहीं हो सकता है।", + "discussions.post.editor.content.error": "पोस्ट सामग्री खाली नहीं हो सकती।", + "discussions.post.editor.questionText": "आपका प्रश्न या विचार (आवश्यक)", + "discussions.post.editor.preview": "पूर्वावलोकन", + "discussions.post.editor.followPost": "इस पोस्ट को फ़ॉलो करें", + "discussions.post.editor.anonymousPost": "गुमनाम रूप से पोस्ट करें", + "discussions.post.editor.anonymousToPeersPost": "साथियों को गुमनाम रूप से पोस्ट करें", + "discussions.editor.posts.editReasonCode": "संपादन का कारण", + "discussions.editor.posts.showPreview.button": "पूर्वावलोकन दिखाएं", + "discussions.topic.noName.label": "अनाम श्रेणी", + "discussions.subtopic.noName.label": "अनाम उपश्रेणी", + "discussions.posts.filter.showALl": "सभी दिखाएं", + "discussions.posts.filter.discussions": "चर्चाएँ", + "discussions.posts.filter.questions": "प्रश्न", + "discussions.posts.filter.message": "स्थिति: {filterBy}", + "discussions.posts.status.filter.anyStatus": "कोई स्थिति", + "discussions.posts.status.filter.unread": "अपठित", + "discussions.posts.status.filter.following": "फ़ॉलोइंग", + "discussions.posts.status.filter.reported": "सूचित किया जा चूका है", + "discussions.posts.status.filter.unanswered": "अनुत्तरित", + "discussions.posts.status.filter.unresponded": "जवाब नहीं दिया", + "discussions.posts.filter.myPosts": "मेरे पोस्ट", + "discussions.posts.filter.myDiscussions": "मेरी चर्चाएँ", + "discussions.posts.filter.myQuestions": "मेरे सवाल", + "discussions.posts.sort.message": "{sortBy} द्वारा क्रमबद्ध", + "discussions.posts.sort.lastActivity": "हाल की गतिविधि", + "discussions.posts.sort.commentCount": "सर्वाधिक गतिविधि", + "discussions.posts.sort.voteCount": "सबसे अधिक पसंद", "discussions.posts.sort-filter.sortFilterStatus": "{own, select, false {All} true {Own} other {{own}} } {status, select, statusAll {} statusUnread {unread} statusFollowing {followed} statusReported {reported} statusUnanswered {unanswered} statusUnresponded {unresponded} other {{status}} } {type, select, discussion {discussions} question {questions} all {posts} other {{type}} } {cohortType, select, all {} group {in {cohort}} other {{cohortType}} } sorted by {sort, select, lastActivityAt {recent activity} commentCount {most activity} voteCount {most likes} other {{sort}} }" } \ No newline at end of file From 6ae5130c147e2b9e03d7944bbf073bc75d8a8f88 Mon Sep 17 00:00:00 2001 From: vladislavkeblysh <138868841+vladislavkeblysh@users.noreply.github.com> Date: Mon, 18 Dec 2023 13:26:38 +0200 Subject: [PATCH 16/18] feat: fixed page styles (#577) --- src/discussions/common/AuthorLabel.jsx | 2 +- .../post-comments/comments/CommentsView.jsx | 2 +- src/index.scss | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/discussions/common/AuthorLabel.jsx b/src/discussions/common/AuthorLabel.jsx index 2730b8296..c3c50a8bf 100644 --- a/src/discussions/common/AuthorLabel.jsx +++ b/src/discussions/common/AuthorLabel.jsx @@ -50,7 +50,7 @@ const AuthorLabel = ({ const authorName = useMemo(() => ( { const handleDefinition = useCallback((message, commentsLength) => (
diff --git a/src/index.scss b/src/index.scss index 645fb2984..9a0b721e6 100755 --- a/src/index.scss +++ b/src/index.scss @@ -340,6 +340,10 @@ header { .nav-item:not(:last-child){ .nav-link { border-right: 0; + + @media screen and (max-width: 567px) { + border-right: solid 1px #e9e6e4; + } } } } @@ -488,6 +492,11 @@ header { z-index: 1; } +.comment-line { + width: calc(100% - 180px); + line-height: 1; +} + .post-preview, .discussion-comments { blockquote { @@ -529,3 +538,8 @@ header { left: 50%; transform: translate(-50%, -50%); } + +.author-name { + line-height: 1; + word-break: break-all; +} From bc997108ef679af303ecd93f6ae2fa201d2f661c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 18:33:51 +0500 Subject: [PATCH 17/18] chore(deps): update dependency @edx/frontend-build to v13.0.14 (#628) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 127aafce2..90c763229 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@edx/browserslist-config": "1.2.0", - "@edx/frontend-build": "13.0.12", + "@edx/frontend-build": "13.0.14", "@edx/reactifex": "1.1.0", "@testing-library/jest-dom": "5.17.0", "@testing-library/react": "12.1.5", @@ -2057,9 +2057,9 @@ } }, "node_modules/@edx/frontend-build": { - "version": "13.0.12", - "resolved": "https://registry.npmjs.org/@edx/frontend-build/-/frontend-build-13.0.12.tgz", - "integrity": "sha512-YrTTmo98YxN6HevY9KAUcssfCAFzHlSqwN+8y5fb3hWoCfBX5XapZdpjP3Uawet0/ESIxV6HFQLJ8N21xVXVsg==", + "version": "13.0.14", + "resolved": "https://registry.npmjs.org/@edx/frontend-build/-/frontend-build-13.0.14.tgz", + "integrity": "sha512-AR/2GvIecX4LxJT4QIoeeBbnUVjjpRnT2P6gaqO8zEeoAS9ugYRQmqvCCeKJnt7vGmEEcincKfWJQu5nfUGfdA==", "dependencies": { "@babel/cli": "7.22.5", "@babel/core": "7.22.5", diff --git a/package.json b/package.json index e597338fe..9b831e355 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ }, "devDependencies": { "@edx/browserslist-config": "1.2.0", - "@edx/frontend-build": "13.0.12", + "@edx/frontend-build": "13.0.14", "@edx/reactifex": "1.1.0", "@testing-library/jest-dom": "5.17.0", "@testing-library/react": "12.1.5", From b5d036a54d983241a5898fed735937f348754901 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 13:35:08 +0000 Subject: [PATCH 18/18] fix(deps): update dependency regenerator-runtime to v0.14.1 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 90c763229..ab68b2949 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "react-router": "6.18.0", "react-router-dom": "6.18.0", "redux": "4.2.1", - "regenerator-runtime": "0.14.0", + "regenerator-runtime": "0.14.1", "timeago.js": "4.0.2", "tinymce": "5.10.7", "yup": "0.31.1" @@ -21329,9 +21329,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regenerator-transform": { "version": "0.15.2", diff --git a/package.json b/package.json index 9b831e355..cd94bacdc 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "react-router": "6.18.0", "react-router-dom": "6.18.0", "redux": "4.2.1", - "regenerator-runtime": "0.14.0", + "regenerator-runtime": "0.14.1", "timeago.js": "4.0.2", "tinymce": "5.10.7", "yup": "0.31.1"