Compare commits
14 Commits
release/ul
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7f172761f | ||
|
|
e5388690b2 | ||
|
|
cefc8d9d35 | ||
|
|
f5c5913d3f | ||
|
|
687dae6b21 | ||
|
|
b812b96d77 | ||
|
|
142abd8dd4 | ||
|
|
ece4432f58 | ||
|
|
c599046813 | ||
|
|
c323c80bc8 | ||
|
|
37cec76dcb | ||
|
|
00440fc15a | ||
|
|
a4826ae62d | ||
|
|
16c49b2404 |
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
version: 2
|
||||
updates:
|
||||
# Adding new check for github-actions
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Nodejs
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: i18n_extract
|
||||
run: npm run i18n_extract
|
||||
- name: Coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: true
|
||||
|
||||
4039
package-lock.json
generated
4039
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -31,17 +31,17 @@
|
||||
"dependencies": {
|
||||
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||
"@edx/frontend-component-footer": "^14.6.0",
|
||||
"@edx/frontend-component-header": "^6.2.0",
|
||||
"@edx/frontend-component-header": "^8.1.0",
|
||||
"@edx/frontend-platform": "^8.3.3",
|
||||
"@edx/openedx-atlas": "^0.6.0",
|
||||
"@edx/openedx-atlas": "^0.7.0",
|
||||
"@openedx/paragon": "^23.4.5",
|
||||
"@reduxjs/toolkit": "1.9.7",
|
||||
"@tinymce/tinymce-react": "5.1.1",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"classnames": "2.5.1",
|
||||
"core-js": "3.21.1",
|
||||
"core-js": "3.47.0",
|
||||
"dompurify": "^2.4.3",
|
||||
"formik": "2.4.5",
|
||||
"formik": "2.4.9",
|
||||
"lodash.snakecase": "4.1.1",
|
||||
"prop-types": "15.8.1",
|
||||
"raw-loader": "4.0.2",
|
||||
@@ -56,20 +56,20 @@
|
||||
"redux": "4.2.1",
|
||||
"regenerator-runtime": "0.14.1",
|
||||
"timeago.js": "4.0.2",
|
||||
"tinymce": "5.10.7",
|
||||
"tinymce": "5.10.9",
|
||||
"yup": "0.32.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@edx/browserslist-config": "1.2.0",
|
||||
"@edx/browserslist-config": "1.5.0",
|
||||
"@openedx/frontend-build": "^14.6.2",
|
||||
"@testing-library/jest-dom": "5.17.0",
|
||||
"@testing-library/react": "14.3.1",
|
||||
"@testing-library/user-event": "13.5.0",
|
||||
"axios": "^0.28.0",
|
||||
"axios": "^0.30.0",
|
||||
"axios-mock-adapter": "1.22.0",
|
||||
"babel-plugin-react-intl": "8.2.25",
|
||||
"eslint-plugin-simple-import-sort": "7.0.0",
|
||||
"glob": "7.2.0",
|
||||
"glob": "7.2.3",
|
||||
"jest": "29.7.0",
|
||||
"rosie": "2.1.1"
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ const FilterBar = ({
|
||||
<ActionItem
|
||||
key={toString(cohort.id)}
|
||||
id={toString(cohort.id)}
|
||||
label={cohort.name}
|
||||
label={capitalize(cohort.name)}
|
||||
value={toString(cohort.id)}
|
||||
selected={selectedFilters.cohort}
|
||||
/>
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
} from 'react';
|
||||
|
||||
import { breakpoints, useWindowSize } from '@openedx/paragon';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import {
|
||||
matchPath, useLocation, useMatch, useNavigate,
|
||||
@@ -21,13 +20,10 @@ import { ContentActions, RequestStatus, Routes } from '../../data/constants';
|
||||
import { selectTopicsUnderCategory } from '../../data/selectors';
|
||||
import fetchCourseBlocks from '../../data/thunks';
|
||||
import DiscussionContext from '../common/context';
|
||||
import { selectTopics as selectInContextTopics } from '../in-context-topics/data/selectors';
|
||||
import fetchCourseTopicsV3 from '../in-context-topics/data/thunks';
|
||||
import PostCommentsContext from '../post-comments/postCommentsContext';
|
||||
import { clearRedirect } from '../posts/data';
|
||||
import { threadsLoadingStatus } from '../posts/data/selectors';
|
||||
import { selectTopics } from '../topics/data/selectors';
|
||||
import fetchCourseTopics from '../topics/data/thunks';
|
||||
import tourCheckpoints from '../tours/constants';
|
||||
import selectTours from '../tours/data/selectors';
|
||||
import { updateTourShowStatus } from '../tours/data/thunks';
|
||||
@@ -36,7 +32,6 @@ import { checkPermissions, discussionsPath } from '../utils';
|
||||
import { ContentSelectors } from './constants';
|
||||
import {
|
||||
selectAreThreadsFiltered,
|
||||
selectDiscussionProvider,
|
||||
selectEnableInContext,
|
||||
selectIsPostingEnabled,
|
||||
selectIsUserLearner,
|
||||
@@ -109,21 +104,6 @@ export function useCourseBlockData(courseId) {
|
||||
}, [courseId, isEnrolled, courseStatus, isUserLearner]);
|
||||
}
|
||||
|
||||
export function useTopicsData(courseId, enableInContextSidebar) {
|
||||
const dispatch = useDispatch();
|
||||
const enableInContext = useSelector(selectEnableInContext);
|
||||
const provider = useSelector(selectDiscussionProvider);
|
||||
const topics = useSelector(enableInContext ? selectInContextTopics : selectTopics);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEmpty(topics) && provider) {
|
||||
dispatch((enableInContext || enableInContextSidebar)
|
||||
? fetchCourseTopicsV3(courseId)
|
||||
: fetchCourseTopics(courseId));
|
||||
}
|
||||
}, [topics, provider, enableInContext, enableInContextSidebar]);
|
||||
}
|
||||
|
||||
export function useRedirectToThread(courseId, enableInContextSidebar) {
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -16,7 +16,7 @@ import { ALL_ROUTES, DiscussionProvider, Routes as ROUTES } from '../../data/con
|
||||
import DiscussionContext from '../common/context';
|
||||
import ContentUnavailable from '../content-unavailable/ContentUnavailable';
|
||||
import {
|
||||
useCourseBlockData, useCourseDiscussionData, useIsOnTablet, useRedirectToThread, useSidebarVisible, useTopicsData,
|
||||
useCourseBlockData, useCourseDiscussionData, useIsOnTablet, useRedirectToThread, useSidebarVisible,
|
||||
} from '../data/hooks';
|
||||
import { selectDiscussionProvider, selectEnableInContext, selectIsUserLearner } from '../data/selectors';
|
||||
import { EmptyLearners, EmptyTopics } from '../empty-posts';
|
||||
@@ -62,7 +62,6 @@ const DiscussionsHome = () => {
|
||||
useCourseDiscussionData(courseId);
|
||||
useRedirectToThread(courseId, enableInContextSidebar);
|
||||
useCourseBlockData(courseId);
|
||||
useTopicsData(courseId, enableInContextSidebar);
|
||||
useFeedbackWrapper();
|
||||
/* Display the content area if we are currently viewing/editing a post or creating one.
|
||||
If the window is larger than a particular size, show the sidebar for navigating between posts/topics.
|
||||
|
||||
@@ -27,10 +27,10 @@ import { fetchThreads } from '../posts/data/thunks';
|
||||
import fetchCourseTopics from '../topics/data/thunks';
|
||||
import DiscussionsHome from './DiscussionsHome';
|
||||
|
||||
import '../../components/NavigationBar/data/__factories__/navigationBar.factory';
|
||||
import '../in-context-topics/data/__factories__/inContextTopics.factory';
|
||||
import '../posts/data/__factories__/threads.factory';
|
||||
import '../in-context-topics/data/__factories__/inContextTopics.factory';
|
||||
import '../topics/data/__factories__/topics.factory';
|
||||
import '../../components/NavigationBar/data/__factories__/navigationBar.factory';
|
||||
|
||||
const courseConfigApiUrl = getCourseConfigApiUrl();
|
||||
let axiosMock;
|
||||
@@ -224,7 +224,7 @@ describe('DiscussionsHome', () => {
|
||||
|
||||
it('should display post editor form when click on add a post button in legacy topics view', async () => {
|
||||
axiosMock.onGet(getDiscussionsConfigUrl(courseId)).reply(200, {
|
||||
enable_in_context: false, hasModerationPrivileges: true, isEmailVerified: true, provider: 'legacy',
|
||||
enable_in_context: false, hasModerationPrivileges: true, isEmailVerified: true,
|
||||
});
|
||||
await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState);
|
||||
await renderComponent(`/${courseId}/topics`);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import React, {
|
||||
useCallback, useContext, useEffect, useMemo,
|
||||
} from 'react';
|
||||
|
||||
import { Spinner } from '@openedx/paragon';
|
||||
import classNames from 'classnames';
|
||||
@@ -7,7 +9,8 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import SearchInfo from '../../components/SearchInfo';
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
import { selectAreThreadsFiltered } from '../data/selectors';
|
||||
import DiscussionContext from '../common/context';
|
||||
import { selectAreThreadsFiltered, selectDiscussionProvider } from '../data/selectors';
|
||||
import { clearFilter, clearSort } from '../posts/data/slices';
|
||||
import NoResults from '../posts/NoResults';
|
||||
import { handleKeyDown } from '../utils';
|
||||
@@ -16,6 +19,7 @@ import {
|
||||
selectNonCoursewareTopics, selectTopicFilter, selectTopics,
|
||||
} from './data/selectors';
|
||||
import { setFilter } from './data/slices';
|
||||
import fetchCourseTopicsV3 from './data/thunks';
|
||||
import { ArchivedBaseGroup, SectionBaseGroup, Topic } from './topic';
|
||||
|
||||
const TopicsList = () => {
|
||||
@@ -67,12 +71,20 @@ const TopicsList = () => {
|
||||
|
||||
const TopicsView = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { courseId } = useContext(DiscussionContext);
|
||||
const provider = useSelector(selectDiscussionProvider);
|
||||
const topicFilter = useSelector(selectTopicFilter);
|
||||
const filteredTopics = useSelector(selectFilteredTopics);
|
||||
const loadingStatus = useSelector(selectLoadingStatus);
|
||||
const isPostsFiltered = useSelector(selectAreThreadsFiltered);
|
||||
const topics = useSelector(selectTopics);
|
||||
|
||||
useEffect(() => {
|
||||
if (provider) {
|
||||
dispatch(fetchCourseTopicsV3(courseId));
|
||||
}
|
||||
}, [provider]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPostsFiltered) {
|
||||
dispatch(clearFilter());
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {
|
||||
import React, {
|
||||
useCallback, useContext, useEffect, useMemo,
|
||||
} from 'react';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
|
||||
import { Button, Spinner } from '@openedx/paragon';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
@@ -14,5 +14,5 @@ export const selectLearnerSorting = () => state => state.learners.sortedBy;
|
||||
export const selectLearnerNextPage = () => state => state.learners.nextPage;
|
||||
|
||||
export const selectLearnerAvatar = author => state => (
|
||||
state.learners.learnerProfiles[author]?.profileImage?.imageUrlSmall
|
||||
state.learners.learnerProfiles[author]?.profileImage?.imageUrlLarge
|
||||
);
|
||||
|
||||
@@ -9,9 +9,7 @@ import {
|
||||
} from 'react-router-dom';
|
||||
import { Factory } from 'rosie';
|
||||
|
||||
import {
|
||||
camelCaseObject, getConfig, initializeMockApp, setConfig,
|
||||
} from '@edx/frontend-platform';
|
||||
import { camelCaseObject, initializeMockApp } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
@@ -740,20 +738,6 @@ describe('ThreadView', () => {
|
||||
expect(screen.queryByTestId('comment-comment-4'))
|
||||
.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('it show avatar for reply author when ENABLE_PROFILE_IMAGE is true', async () => {
|
||||
setConfig({
|
||||
...getConfig(),
|
||||
ENABLE_PROFILE_IMAGE: 'true',
|
||||
});
|
||||
await waitFor(() => renderComponent(discussionPostId));
|
||||
|
||||
const comment = await waitFor(() => screen.findByTestId('comment-comment-1'));
|
||||
|
||||
expect(comment).toBeInTheDocument();
|
||||
const replyAuthorAvatar = within(comment).getAllByAltText('edx');
|
||||
expect(replyAuthorAvatar.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('for question thread', () => {
|
||||
|
||||
@@ -46,7 +46,7 @@ const Comment = ({
|
||||
const {
|
||||
id, parentId, childCount, abuseFlagged, endorsed, threadId, endorsedAt, endorsedBy, endorsedByLabel, renderedBody,
|
||||
voted, following, voteCount, authorLabel, author, createdAt, lastEdit, rawBody, closed, closedBy, closeReason,
|
||||
editByLabel, closedByLabel, users: commentUsers,
|
||||
editByLabel, closedByLabel, users: postUsers,
|
||||
} = comment;
|
||||
const intl = useIntl();
|
||||
const hasChildren = childCount > 0;
|
||||
@@ -209,7 +209,7 @@ const Comment = ({
|
||||
closed={closed}
|
||||
createdAt={createdAt}
|
||||
lastEdit={lastEdit}
|
||||
commentUsers={commentUsers}
|
||||
postUsers={postUsers}
|
||||
/>
|
||||
{isEditing ? (
|
||||
<CommentEditor
|
||||
|
||||
@@ -19,7 +19,7 @@ const CommentHeader = ({
|
||||
closed,
|
||||
createdAt,
|
||||
lastEdit,
|
||||
commentUsers,
|
||||
postUsers,
|
||||
}) => {
|
||||
const colorClass = AvatarOutlineAndLabelColors[authorLabel];
|
||||
const hasAnyAlert = useAlertBannerVisible({
|
||||
@@ -31,7 +31,7 @@ const CommentHeader = ({
|
||||
const authorAvatar = useSelector(selectAuthorAvatar(author));
|
||||
|
||||
const profileImage = getConfig()?.ENABLE_PROFILE_IMAGE === 'true'
|
||||
? Object.values(commentUsers ?? {})[0]?.profile?.image
|
||||
? Object.values(postUsers ?? {})[0]?.profile?.image
|
||||
: null;
|
||||
|
||||
return (
|
||||
@@ -43,7 +43,7 @@ const CommentHeader = ({
|
||||
<Avatar
|
||||
className={`border-0 ml-0.5 mr-2.5 ${colorClass ? `outline-${colorClass}` : 'outline-anonymous'}`}
|
||||
alt={author}
|
||||
src={profileImage?.hasImage ? profileImage?.imageUrlSmall : authorAvatar?.imageUrlSmall}
|
||||
src={profileImage?.hasImage ? profileImage?.imageUrlSmall : authorAvatar}
|
||||
style={{
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
@@ -72,7 +72,7 @@ CommentHeader.propTypes = {
|
||||
editorUsername: PropTypes.string,
|
||||
reason: PropTypes.string,
|
||||
}),
|
||||
commentUsers: PropTypes.shape({}).isRequired,
|
||||
postUsers: PropTypes.shape({}).isRequired,
|
||||
};
|
||||
|
||||
CommentHeader.defaultProps = {
|
||||
|
||||
@@ -22,7 +22,7 @@ const defaultProps = {
|
||||
closed: false,
|
||||
createdAt: '2025-09-23T10:00:00Z',
|
||||
lastEdit: null,
|
||||
commentUsers: {
|
||||
postUsers: {
|
||||
'test-user': {
|
||||
profile: { image: { hasImage: true, imageUrlSmall: 'http://avatar.test/img.png' } },
|
||||
},
|
||||
|
||||
@@ -5,7 +5,6 @@ import { Avatar, useToggle } from '@openedx/paragon';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import * as timeago from 'timeago.js';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import HTMLLoader from '../../../../components/HTMLLoader';
|
||||
@@ -25,7 +24,7 @@ import CommentEditor from './CommentEditor';
|
||||
const Reply = ({ responseId }) => {
|
||||
timeago.register('time-locale', timeLocale);
|
||||
const {
|
||||
id, abuseFlagged, author, authorLabel, endorsed, lastEdit, closed, closedBy, users: replyUsers,
|
||||
id, abuseFlagged, author, authorLabel, endorsed, lastEdit, closed, closedBy,
|
||||
closeReason, createdAt, threadId, parentId, rawBody, renderedBody, editByLabel, closedByLabel,
|
||||
} = useSelector(selectCommentOrResponseById(responseId));
|
||||
const intl = useIntl();
|
||||
@@ -79,10 +78,6 @@ const Reply = ({ responseId }) => {
|
||||
[ContentActions.REPORT]: handleAbusedFlag,
|
||||
}), [handleEditContent, handleReplyEndorse, showDeleteConfirmation, handleAbusedFlag]);
|
||||
|
||||
const profileImage = getConfig()?.ENABLE_PROFILE_IMAGE === 'true'
|
||||
? Object.values(replyUsers ?? {})[0]?.profile?.image
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="d-flex flex-column mt-2.5 " data-testid={`reply-${id}`} role="listitem">
|
||||
<Confirmation
|
||||
@@ -128,7 +123,7 @@ const Reply = ({ responseId }) => {
|
||||
<Avatar
|
||||
className={`ml-0.5 mt-0.5 border-0 ${colorClass ? `outline-${colorClass}` : 'outline-anonymous'}`}
|
||||
alt={author}
|
||||
src={profileImage?.hasImage ? profileImage?.imageUrlSmall : authorAvatar?.imageUrlSmall}
|
||||
src={authorAvatar?.imageUrlSmall}
|
||||
style={{
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
|
||||
@@ -30,16 +30,6 @@ Factory.define('comment')
|
||||
parent_id: null,
|
||||
children: [],
|
||||
abuse_flagged_any_user: false,
|
||||
users: {
|
||||
edx: {
|
||||
profile: {
|
||||
image: {
|
||||
hasImage: true,
|
||||
imageUrlSmall: 'http://test.site/default-avatar-small.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Factory.define('commentsResult')
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import React, { useCallback, useContext, useMemo } from 'react';
|
||||
import React, {
|
||||
useCallback, useContext, useEffect, useMemo,
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import SearchInfo from '../../components/SearchInfo';
|
||||
import { selectCurrentCategoryGrouping, selectTopicsUnderCategory } from '../../data/selectors';
|
||||
import DiscussionContext from '../common/context';
|
||||
import { selectEnableInContext } from '../data/selectors';
|
||||
import { selectTopics as selectInContextTopics } from '../in-context-topics/data/selectors';
|
||||
import fetchCourseTopicsV3 from '../in-context-topics/data/thunks';
|
||||
import { selectTopics } from '../topics/data/selectors';
|
||||
import fetchCourseTopics from '../topics/data/thunks';
|
||||
import { handleKeyDown } from '../utils';
|
||||
import { selectAllThreadsIds, selectTopicThreadsIds } from './data/selectors';
|
||||
import { setSearchQuery } from './data/slices';
|
||||
@@ -43,12 +51,27 @@ CategoryPostsList.propTypes = {
|
||||
};
|
||||
|
||||
const PostsView = () => {
|
||||
const { topicId, category } = useContext(DiscussionContext);
|
||||
const {
|
||||
topicId,
|
||||
category,
|
||||
courseId,
|
||||
enableInContextSidebar,
|
||||
} = useContext(DiscussionContext);
|
||||
const dispatch = useDispatch();
|
||||
const enableInContext = useSelector(selectEnableInContext);
|
||||
const searchString = useSelector(({ threads }) => threads.filters.search);
|
||||
const resultsFound = useSelector(({ threads }) => threads.totalThreads);
|
||||
const textSearchRewrite = useSelector(({ threads }) => threads.textSearchRewrite);
|
||||
const loadingStatus = useSelector(({ threads }) => threads.status);
|
||||
const topics = useSelector(enableInContext ? selectInContextTopics : selectTopics);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEmpty(topics)) {
|
||||
dispatch((enableInContext || enableInContextSidebar)
|
||||
? fetchCourseTopicsV3(courseId)
|
||||
: fetchCourseTopics(courseId));
|
||||
}
|
||||
}, [topics]);
|
||||
|
||||
const handleOnClear = useCallback(() => {
|
||||
dispatch(setSearchQuery(''));
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
@@ -230,7 +232,7 @@ describe('PostsView', () => {
|
||||
|
||||
test('test that the cohorts filter works', async () => {
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByLabelText('cohort 1'));
|
||||
fireEvent.click(screen.getByLabelText('Cohort 1'));
|
||||
});
|
||||
|
||||
dropDownButton = screen.getByRole('button', {
|
||||
@@ -278,7 +280,7 @@ describe('PostsView', () => {
|
||||
queryParam: { group_id: undefined },
|
||||
},
|
||||
{
|
||||
label: 'cohort 1',
|
||||
label: 'Cohort 1',
|
||||
queryParam: { group_id: 'cohort-1' },
|
||||
},
|
||||
])(
|
||||
|
||||
@@ -165,7 +165,7 @@ const PostFilterBar = () => {
|
||||
<ActionItem
|
||||
key={cohort.id}
|
||||
id={toString(cohort.id)}
|
||||
label={cohort.name}
|
||||
label={capitalize(cohort.name)}
|
||||
value={toString(cohort.id)}
|
||||
selected={currentFilters.cohort}
|
||||
/>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import React, {
|
||||
useCallback, useContext, useEffect, useMemo,
|
||||
} from 'react';
|
||||
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import SearchInfo from '../../components/SearchInfo';
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
import DiscussionContext from '../common/context';
|
||||
import { selectDiscussionProvider } from '../data/selectors';
|
||||
import NoResults from '../posts/NoResults';
|
||||
import { handleKeyDown } from '../utils';
|
||||
import { selectCategories, selectNonCoursewareTopics, selectTopicFilter } from './data/selectors';
|
||||
import { setFilter, setTopicsCount } from './data/slices';
|
||||
import fetchCourseTopics from './data/thunks';
|
||||
import LegacyTopicGroup from './topic-group/LegacyTopicGroup';
|
||||
import Topic from './topic-group/topic/Topic';
|
||||
import countFilteredTopics from './utils';
|
||||
@@ -60,11 +64,19 @@ const TopicsView = () => {
|
||||
const topicsSelector = useSelector(({ topics }) => topics);
|
||||
const filteredTopicsCount = useSelector(({ topics }) => topics.results.count);
|
||||
const loadingStatus = useSelector(({ topics }) => topics.status);
|
||||
const { courseId } = useContext(DiscussionContext);
|
||||
|
||||
const handleOnClear = useCallback(() => {
|
||||
dispatch(setFilter(''));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Don't load till the provider information is available
|
||||
if (provider) {
|
||||
dispatch(fetchCourseTopics(courseId));
|
||||
}
|
||||
}, [provider]);
|
||||
|
||||
useEffect(() => {
|
||||
const count = countFilteredTopics(topicsSelector, provider);
|
||||
dispatch(setTopicsCount(count));
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { mergeConfig } from '@edx/frontend-platform';
|
||||
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import 'babel-polyfill';
|
||||
|
||||
@@ -68,10 +66,3 @@ global.ResizeObserver = jest.fn().mockImplementation(() => ({
|
||||
}));
|
||||
|
||||
jest.setTimeout(1000000);
|
||||
|
||||
mergeConfig({
|
||||
LEARNING_BASE_URL: process.env.LEARNING_BASE_URL,
|
||||
LEARNER_FEEDBACK_URL: process.env.LEARNER_FEEDBACK_URL,
|
||||
STAFF_FEEDBACK_URL: process.env.STAFF_FEEDBACK_URL,
|
||||
ENABLE_PROFILE_IMAGE: process.env.ENABLE_PROFILE_IMAGE || 'false',
|
||||
}, 'DiscussionsConfig');
|
||||
|
||||
Reference in New Issue
Block a user