Skip to content

Commit 7e385e8

Browse files
committed
Merge branch 'master' into chris/update-cancel-confirmation-button-msg
2 parents 8e4a9c2 + 3685dbd commit 7e385e8

File tree

140 files changed

+4171
-1657
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

140 files changed

+4171
-1657
lines changed

package-lock.json

Lines changed: 1796 additions & 820 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@
4949
"@dnd-kit/utilities": "^3.2.2",
5050
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.3",
5151
"@edx/browserslist-config": "1.2.0",
52-
"@edx/frontend-component-footer": "^14.1.0",
53-
"@edx/frontend-component-header": "^5.8.3",
52+
"@edx/frontend-component-footer": "^14.3.0",
53+
"@edx/frontend-component-header": "^6.2.0",
5454
"@edx/frontend-enterprise-hotjar": "^2.0.0",
55-
"@edx/frontend-platform": "^8.0.3",
55+
"@edx/frontend-platform": "^8.3.1",
5656
"@edx/openedx-atlas": "^0.6.0",
5757
"@openedx-plugins/course-app-calculator": "file:plugins/course-apps/calculator",
5858
"@openedx-plugins/course-app-edxnotes": "file:plugins/course-apps/edxnotes",
@@ -64,9 +64,9 @@
6464
"@openedx-plugins/course-app-teams": "file:plugins/course-apps/teams",
6565
"@openedx-plugins/course-app-wiki": "file:plugins/course-apps/wiki",
6666
"@openedx-plugins/course-app-xpert_unit_summary": "file:plugins/course-apps/xpert_unit_summary",
67-
"@openedx/frontend-build": "^14.2.0",
68-
"@openedx/frontend-plugin-framework": "^1.2.1",
69-
"@openedx/paragon": "^22.8.1",
67+
"@openedx/frontend-build": "^14.3.3",
68+
"@openedx/frontend-plugin-framework": "^1.6.0",
69+
"@openedx/paragon": "^22.16.0",
7070
"@redux-devtools/extension": "^3.3.0",
7171
"@reduxjs/toolkit": "1.9.7",
7272
"@tanstack/react-query": "4.36.1",

plugins/course-apps/ora_settings/Settings.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ describe('ORASettings', () => {
142142
renderComponent();
143143
await mockStore({ apiStatus: 200, enabled: false });
144144

145-
const label = screen.getByText(messages.enableFlexPeerGradeLabel.defaultMessage);
145+
const label = await screen.findByText(messages.enableFlexPeerGradeLabel.defaultMessage);
146146
const enableBadge = screen.queryByTestId('enable-badge');
147147

148148
expect(label).toBeVisible();

plugins/course-apps/proctoring/Settings.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ describe('ProctoredExamSettings', () => {
547547
await act(async () => {
548548
render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />));
549549
// This expectation is _inside_ the `act` intentionally, so that it executes immediately.
550-
const spinner = screen.getByRole('status');
550+
const spinner = await screen.findByRole('status');
551551
expect(spinner.textContent).toEqual('Loading...');
552552
});
553553
});

src/CourseAuthoringPage.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { fetchCourseDetail, fetchWaffleFlags } from './data/thunks';
1111
import { useModel } from './generic/model-store';
1212
import NotFoundAlert from './generic/NotFoundAlert';
1313
import PermissionDeniedAlert from './generic/PermissionDeniedAlert';
14-
import { fetchStudioHomeData } from './studio-home/data/thunks';
14+
import { fetchOnlyStudioHomeData } from './studio-home/data/thunks';
1515
import { getCourseAppsApiStatus } from './pages-and-resources/data/selectors';
1616
import { RequestStatus } from './data/constants';
1717
import Loading from './generic/Loading';
@@ -25,7 +25,7 @@ const CourseAuthoringPage = ({ courseId, children }) => {
2525
}, [courseId]);
2626

2727
useEffect(() => {
28-
dispatch(fetchStudioHomeData());
28+
dispatch(fetchOnlyStudioHomeData());
2929
}, []);
3030

3131
const courseDetail = useModel('courseDetails', courseId);

src/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export const COURSE_BLOCK_NAMES = ({
5959
sequential: { id: 'sequential', name: 'Subsection' },
6060
vertical: { id: 'vertical', name: 'Unit' },
6161
libraryContent: { id: 'library_content', name: 'Library content' },
62+
splitTest: { id: 'split_test', name: 'Split Test' },
6263
component: { id: 'component', name: 'Component' },
6364
});
6465

src/content-tags-drawer/ContentTagsDrawer.test.jsx

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,15 @@ describe('<ContentTagsDrawer />', () => {
6161
});
6262

6363
it('shows spinner before the content data query is complete', async () => {
64-
await act(async () => {
65-
renderDrawer(stagedTagsId);
66-
const spinner = screen.getAllByRole('status')[0];
67-
expect(spinner.textContent).toEqual('Loading'); // Uses <Spinner />
68-
});
64+
renderDrawer(stagedTagsId);
65+
const spinner = (await screen.findAllByRole('status'))[0];
66+
expect(spinner.textContent).toEqual('Loading'); // Uses <Spinner />
6967
});
7068

7169
it('shows spinner before the taxonomy tags query is complete', async () => {
72-
await act(async () => {
73-
renderDrawer(stagedTagsId);
74-
const spinner = screen.getAllByRole('status')[1];
75-
expect(spinner.textContent).toEqual('Loading...'); // Uses <Loading />
76-
});
70+
renderDrawer(stagedTagsId);
71+
const spinner = (await screen.findAllByRole('status'))[1];
72+
expect(spinner.textContent).toEqual('Loading...'); // Uses <Loading />
7773
});
7874

7975
it('shows the content display name after the query is complete in drawer variant', async () => {

src/course-libraries/CourseLibraries.test.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,16 @@ describe('<CourseLibraries />', () => {
7676

7777
it('shows alert when out of sync components are present', async () => {
7878
await renderCourseLibrariesPage(mockGetEntityLinks.courseKey);
79+
const allTab = await screen.findByRole('tab', { name: 'Libraries' });
80+
const reviewTab = await screen.findByRole('tab', { name: 'Review Content Updates 5' });
81+
// review tab should be open by default as outOfSyncCount is greater than 0
82+
expect(reviewTab).toHaveAttribute('aria-selected', 'true');
83+
84+
userEvent.click(allTab);
7985
const alert = await screen.findByRole('alert');
8086
expect(await within(alert).findByText(
8187
'5 library components are out of sync. Review updates to accept or ignore changes',
8288
)).toBeInTheDocument();
83-
const allTab = await screen.findByRole('tab', { name: 'Libraries' });
8489
expect(allTab).toHaveAttribute('aria-selected', 'true');
8590

8691
const reviewBtn = await screen.findByRole('button', { name: 'Review' });
@@ -89,31 +94,29 @@ describe('<CourseLibraries />', () => {
8994
expect(allTab).toHaveAttribute('aria-selected', 'false');
9095
expect(await screen.findByRole('tab', { name: 'Review Content Updates 5' })).toHaveAttribute('aria-selected', 'true');
9196
expect(alert).not.toBeInTheDocument();
92-
93-
// go back to all tab
94-
userEvent.click(allTab);
95-
// alert should not be back
96-
expect(alert).not.toBeInTheDocument();
97-
expect(allTab).toHaveAttribute('aria-selected', 'true');
98-
99-
// review updates button
100-
const reviewActionBtn = await screen.findByRole('button', { name: 'Review Updates' });
101-
userEvent.click(reviewActionBtn);
102-
expect(await screen.findByRole('tab', { name: 'Review Content Updates 5' })).toHaveAttribute('aria-selected', 'true');
10397
});
10498

10599
it('hide alert on dismiss', async () => {
106100
await renderCourseLibrariesPage(mockGetEntityLinks.courseKey);
101+
const reviewTab = await screen.findByRole('tab', { name: 'Review Content Updates 5' });
102+
// review tab should be open by default as outOfSyncCount is greater than 0
103+
expect(reviewTab).toHaveAttribute('aria-selected', 'true');
104+
const allTab = await screen.findByRole('tab', { name: 'Libraries' });
105+
userEvent.click(allTab);
106+
expect(allTab).toHaveAttribute('aria-selected', 'true');
107+
107108
const alert = await screen.findByRole('alert');
108109
expect(await within(alert).findByText(
109110
'5 library components are out of sync. Review updates to accept or ignore changes',
110111
)).toBeInTheDocument();
111112
const dismissBtn = await screen.findByRole('button', { name: 'Dismiss' });
112113
userEvent.click(dismissBtn);
113-
const allTab = await screen.findByRole('tab', { name: 'Libraries' });
114114
expect(allTab).toHaveAttribute('aria-selected', 'true');
115-
116-
expect(alert).not.toBeInTheDocument();
115+
waitFor(() => expect(alert).not.toBeInTheDocument());
116+
// review updates button
117+
const reviewActionBtn = await screen.findByRole('button', { name: 'Review Updates' });
118+
userEvent.click(reviewActionBtn);
119+
expect(await screen.findByRole('tab', { name: 'Review Content Updates 5' })).toHaveAttribute('aria-selected', 'true');
117120
});
118121
});
119122

src/course-libraries/CourseLibraries.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, {
2-
useCallback, useMemo, useState,
2+
useCallback, useEffect, useMemo, useState,
33
} from 'react';
44
import { Helmet } from 'react-helmet';
55
import { getConfig } from '@edx/frontend-platform';
@@ -105,7 +105,7 @@ export const CourseLibraries: React.FC<Props> = ({ courseId }) => {
105105
const courseDetails = useModel('courseDetails', courseId);
106106
const [searchParams] = useSearchParams();
107107
const [tabKey, setTabKey] = useState<CourseLibraryTabs>(
108-
() => searchParams.get('tab') as CourseLibraryTabs || CourseLibraryTabs.all,
108+
() => searchParams.get('tab') as CourseLibraryTabs,
109109
);
110110
const [showReviewAlert, setShowReviewAlert] = useState(false);
111111
const { data: libraries, isLoading } = useEntityLinksSummaryByDownstreamContext(courseId);
@@ -124,6 +124,19 @@ export const CourseLibraries: React.FC<Props> = ({ courseId }) => {
124124
setTabKey(selectedTab);
125125
}, []);
126126

127+
useEffect(() => {
128+
setTabKey((prev) => {
129+
if (outOfSyncCount > 0) {
130+
return CourseLibraryTabs.review;
131+
}
132+
if (prev) {
133+
return prev;
134+
}
135+
/* istanbul ignore next */
136+
return CourseLibraryTabs.all;
137+
});
138+
}, [outOfSyncCount]);
139+
127140
const renderLibrariesTabContent = useCallback(() => {
128141
if (isLoading) {
129142
return <Loading />;

src/course-libraries/OutOfSyncAlert.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,17 @@ interface OutOfSyncAlertProps {
1313
onDismiss?: () => void;
1414
onReview: () => void;
1515
}
16-
/*
17-
Shows an alert when library components used in the current course were updated and the blocks in course can be updated.
18-
Dismiss or review action is persisted using localStorage to avoid displaying the alert on every refresh.
16+
/**
17+
* Shows an alert when library components used in the current course were updated and the blocks
18+
* in course can be updated. Following are the conditions for displaying the alert.
19+
*
20+
* * The alert is displayed if components are out of sync.
21+
* * If the user clicks on dismiss button, the state is stored in localstorage of user
22+
* in this format: outOfSyncCountAlert-${courseId} = <number of out of sync components>.
23+
* * If the number of sync components don't change for the course and the user opens outline
24+
* in the same browser, they don't see the alert again.
25+
* * If the number changes, i.e., if a new component is out of sync or the user updates or ignores
26+
* a component, the alert is displayed again.
1927
*/
2028
export const OutOfSyncAlert: React.FC<OutOfSyncAlertProps> = ({
2129
showAlert,
@@ -48,11 +56,6 @@ export const OutOfSyncAlert: React.FC<OutOfSyncAlertProps> = ({
4856
onDismiss?.();
4957
};
5058

51-
const reviewAlert = () => {
52-
dismissAlert();
53-
onReview();
54-
};
55-
5659
return (
5760
<AlertMessage
5861
title={intl.formatMessage(messages.outOfSyncCountAlertTitle, { outOfSyncCount })}
@@ -63,7 +66,7 @@ export const OutOfSyncAlert: React.FC<OutOfSyncAlertProps> = ({
6366
onClose={dismissAlert}
6467
actions={[
6568
<Button
66-
onClick={reviewAlert}
69+
onClick={onReview}
6770
>
6871
{intl.formatMessage(messages.outOfSyncCountAlertReviewBtn)}
6972
</Button>,

0 commit comments

Comments
 (0)