Skip to content

Commit

Permalink
feat: [AXIMST-27] Unit page - render xblock content (#121)
Browse files Browse the repository at this point in the history
fix: [AXIMST-27] Unit page - change iframe pararm for display xblock content (#151)

feat: [AXIMST-52] display unit and xblock render errors (#191)

* feat: [AXIMST-52] display unit and xblock render errors

* fix: after discussion

* fix: after review

feat: Course unit - Rendering xblocks in iframes (#201)

* feat: added xblock render engine

* feat: connected iframe template

* feat: CSS and JS transfering

* feat: show video xblock

* feat: added multiply xblocks

* feat: rendering advanced components

* fix: add solution for request from within the iframe

* feat: iframe height

* refactor: code refactoring

* fix: fixed platform ajax prefix

* refactor: global refactoring

* refactor: show LTI xblock

* refactor: removed old xblock-content

* refactor: code refactoring

* refactor: some refactoring

* refactor: refactoring

* refactor: code refactoring

* refactor: refactoring after review

---------

Co-authored-by: monteri <lansevermore>

feat: [AXIMST-739] added xblock actions (#218)

* feat: [AXIMST-739] added xblock actions

* refactor: code refactoring

* refactor: refactoring after review

fix: after cherru-pick

fix: after cherry-pick

refactor: removed canEdit mock (#224)

fix: [AXIMST-655] fixed position of the view-port after loading the unit page (#217)

fix: [AXIMST-719] Course unit - Xblock problems (#213)

* fix: [AXIMST-719] fixed xblock problems

* fix: added asset and static replacer

* feat: added style extractor

* refactor: code refactoring

* refactor: after review

fix: [AXIMST-718] Course unit - Created logic for getting CSRF token (#226)

* fix: created logic for getting csrf token

* fix: usage of csrfTokenData

* refactor: code refactoring

---------

Co-authored-by: monteri <lansevermore>

fix: [AXIMST-745] added studioBaseUrl for static paths (#228)

refactor: [AXIMST-746] Unit page performance refactoring (#229)

Co-authored-by: Kyrylo Hudym-Levkovych <[email protected]>

fix: [AXIMST-785] fixed discard logic (#232)

feat: [AXIMST-800] Course unit - Added Collapse and Expand all buttons for xblocks (#234)

* feat: [AXIMST-800] added Collapse and Expand all buttons for xblocks

* feat: added tests

refactor: code refactoring
  • Loading branch information
ihor-romaniuk authored and PKulkoRaccoonGang committed Apr 30, 2024
1 parent a9a73ef commit 20af604
Show file tree
Hide file tree
Showing 42 changed files with 1,650 additions and 81 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ INVITE_STUDENTS_EMAIL_TO=''
AI_TRANSLATIONS_BASE_URL=''
ENABLE_HOME_PAGE_COURSE_API_V2=false
ENABLE_CHECKLIST_QUALITY=''
SECURE_ORIGIN_XBLOCK_BOOTSTRAP_HTML_URL=null
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ INVITE_STUDENTS_EMAIL_TO="[email protected]"
AI_TRANSLATIONS_BASE_URL='http://localhost:18760'
ENABLE_HOME_PAGE_COURSE_API_V2=false
ENABLE_CHECKLIST_QUALITY=true
SECURE_ORIGIN_XBLOCK_BOOTSTRAP_HTML_URL=/xblock-bootstrap.html
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ BBB_LEARN_MORE_URL=''
INVITE_STUDENTS_EMAIL_TO="[email protected]"
ENABLE_HOME_PAGE_COURSE_API_V2=true
ENABLE_CHECKLIST_QUALITY=true
SECURE_ORIGIN_XBLOCK_BOOTSTRAP_HTML_URL=/xblock-bootstrap.html
121 changes: 121 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
"@testing-library/user-event": "^13.2.1",
"axios": "^0.28.0",
"axios-mock-adapter": "1.22.0",
"copy-webpack-plugin": "^11.0.0",
"eslint-import-resolver-webpack": "^0.13.8",
"fetch-mock-jest": "^1.5.1",
"glob": "7.2.3",
Expand Down
36 changes: 33 additions & 3 deletions src/course-unit/CourseUnit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ import { useEffect, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
import { Container, Layout, Stack } from '@openedx/paragon';
import {
Container, Layout, Stack, Button,
} from '@openedx/paragon';
import { useIntl, injectIntl } from '@edx/frontend-platform/i18n';
import { DraggableList, ErrorAlert } from '@edx/frontend-lib-content-components';
import { Warning as WarningIcon } from '@openedx/paragon/icons';
import {
Warning as WarningIcon,
ArrowDropDown as ArrowDownIcon,
ArrowDropUp as ArrowUpIcon,
} from '@openedx/paragon/icons';
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';

import { getProcessingNotification } from '../generic/processing-notification/data/selectors';
Expand Down Expand Up @@ -60,6 +66,9 @@ const CourseUnit = ({ courseId }) => {
courseVerticalChildren,
handleXBlockDragAndDrop,
canPasteComponent,
isXBlocksExpanded,
isXBlocksRendered,
handleExpandAll,
} = useCourseUnit({ courseId, blockId });

const initialXBlocksData = useMemo(() => courseVerticalChildren.children ?? [], [courseVerticalChildren.children]);
Expand All @@ -73,6 +82,10 @@ const CourseUnit = ({ courseId }) => {
setUnitXBlocks(courseVerticalChildren.children);
}, [courseVerticalChildren.children]);

useEffect(() => {
window.scrollTo({ top: 0, behavior: 'smooth' });
}, []);

const {
isShow: isShowProcessingNotification,
title: processingNotificationTitle,
Expand Down Expand Up @@ -141,6 +154,7 @@ const CourseUnit = ({ courseId }) => {
{currentlyVisibleToStudents && (
<AlertMessage
className="course-unit__alert"
data-testid="course-unit-unpublished-alert"
title={intl.formatMessage(messages.alertUnpublishedVersion)}
variant="warning"
icon={WarningIcon}
Expand All @@ -158,26 +172,42 @@ const CourseUnit = ({ courseId }) => {
setState={setUnitXBlocks}
updateOrder={finalizeXBlockOrder}
>
{unitXBlocks.length ? (
<Button
variant="outline-primary"
iconBefore={isXBlocksExpanded ? ArrowUpIcon : ArrowDownIcon}
onClick={handleExpandAll}
>
{isXBlocksExpanded
? intl.formatMessage(messages.collapseAllButton)
: intl.formatMessage(messages.expandAllButton)}
</Button>
) : null}
<SortableContext
id="root"
items={unitXBlocks}
strategy={verticalListSortingStrategy}
>
{unitXBlocks.map(({
name, id, blockType: type, shouldScroll, userPartitionInfo, validationMessages,
name, id, blockType: type, renderError, shouldScroll,
userPartitionInfo, validationMessages, actions,
}) => (
<CourseXBlock
id={id}
key={id}
title={name}
type={type}
renderError={renderError}
blockId={blockId}
validationMessages={validationMessages}
shouldScroll={shouldScroll}
handleConfigureSubmit={handleConfigureSubmit}
unitXBlockActions={unitXBlockActions}
data-testid="course-xblock"
userPartitionInfo={userPartitionInfo}
actions={actions}
isXBlocksExpanded={isXBlocksExpanded}
isXBlocksRendered={isXBlocksRendered}
/>
))}
</SortableContext>
Expand Down
88 changes: 85 additions & 3 deletions src/course-unit/CourseUnit.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -520,10 +520,10 @@ describe('<CourseUnit />', () => {
});

it('should display a warning alert for unpublished course unit version', async () => {
const { getByRole } = render(<RootWrapper />);
const { getByTestId } = render(<RootWrapper />);

await waitFor(() => {
const unpublishedAlert = getByRole('alert', { class: 'course-unit-unpublished-alert' });
const unpublishedAlert = getByTestId('course-unit-unpublished-alert');
expect(unpublishedAlert).toHaveTextContent(messages.alertUnpublishedVersion.defaultMessage);
expect(unpublishedAlert).toHaveClass('alert-warning');
});
Expand All @@ -542,7 +542,7 @@ describe('<CourseUnit />', () => {
await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch);

await waitFor(() => {
const unpublishedAlert = queryByRole('alert', { class: 'course-unit-unpublished-alert' });
const unpublishedAlert = queryByRole('alert', { name: messages.alertUnpublishedVersion });
expect(unpublishedAlert).toBeNull();
});
});
Expand Down Expand Up @@ -594,6 +594,7 @@ describe('<CourseUnit />', () => {
block_id: '1234567890',
block_type: 'drag-and-drop-v2',
user_partition_info: {},
actions: courseVerticalChildrenMock.children[0].actions,
},
],
});
Expand Down Expand Up @@ -966,6 +967,55 @@ describe('<CourseUnit />', () => {
)).toBeInTheDocument();
});

it('should hide action buttons when their corresponding properties are set to false', async () => {
const {
getByText,
getAllByLabelText,
queryByRole,
} = render(<RootWrapper />);

const convertedXBlockActions = camelCaseObject(courseVerticalChildrenMock.children[0].actions);

const updatedXBlockActions = Object.keys(convertedXBlockActions).reduce((acc, key) => {
acc[key] = false;
return acc;
}, {});

axiosMock
.onGet(getCourseVerticalChildrenApiUrl(blockId))
.reply(200, {
children: [
{
...courseVerticalChildrenMock.children[0],
actions: updatedXBlockActions,
},
],
});

await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch);

await waitFor(() => {
expect(getByText(unitDisplayName)).toBeInTheDocument();
const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage);
userEvent.click(xblockActionBtn);
const deleteBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonDelete.defaultMessage });
const duplicateBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonDuplicate.defaultMessage });
const moveBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonMove.defaultMessage });
const copyToClipboardBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonCopyToClipboard.defaultMessage });
const manageAccessBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonManageAccess.defaultMessage });
// ToDo: uncomment next lines when manage tags will be realized
// eslint-disable-next-line max-len
// const manageTagsBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonManageTags.defaultMessage });

expect(deleteBtn).not.toBeInTheDocument();
expect(duplicateBtn).not.toBeInTheDocument();
expect(moveBtn).not.toBeInTheDocument();
expect(copyToClipboardBtn).not.toBeInTheDocument();
expect(manageAccessBtn).not.toBeInTheDocument();
// expect(manageTagsBtn).not.toBeInTheDocument();
});
});

it('should toggle visibility from header configure modal and update course unit state accordingly', async () => {
const { getByRole, getByTestId } = render(<RootWrapper />);
let courseUnitSidebar;
Expand Down Expand Up @@ -1152,6 +1202,7 @@ describe('<CourseUnit />', () => {
selected_partition_index: -1,
selected_groups_label: '',
},
actions: courseVerticalChildrenMock.children[0].actions,
},
],
});
Expand Down Expand Up @@ -1499,4 +1550,35 @@ describe('<CourseUnit />', () => {
expect(xBlock1).toBe(xBlock2);
});
});

it('should expand xblocks when "Expand all" button is clicked', async () => {
const { getByRole, getAllByTestId } = render(<RootWrapper />);

axiosMock
.onGet(getCourseVerticalChildrenApiUrl(blockId))
.reply(200, courseVerticalChildrenMock);

await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch);

const expandAllXBlocksBtn = getByRole('button', { name: messages.expandAllButton.defaultMessage });
const unitXBlocks = getAllByTestId('course-xblock');

unitXBlocks.forEach((unitXBlock) => {
const unitXBlockContentSections = unitXBlock.querySelectorAll('.pgn__card-section');
expect(unitXBlockContentSections).toHaveLength(0);
});

userEvent.click(expandAllXBlocksBtn);

await waitFor(() => {
const collapseAllXBlocksBtn = getByRole('button', { name: messages.collapseAllButton.defaultMessage });
expect(collapseAllXBlocksBtn).toBeInTheDocument();

unitXBlocks.forEach((unitXBlock) => {
const unitXBlockContentSections = unitXBlock.querySelectorAll('.pgn__card-section');
// xblock content appears inside the xblock element
expect(unitXBlockContentSections.length).toBeGreaterThan(0);
});
});
});
});
2 changes: 2 additions & 0 deletions src/course-unit/__mocks__/courseVerticalChildren.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
can_duplicate: true,
can_move: true,
can_manage_access: true,
can_manage_tags: true,
can_delete: true,
},
user_partition_info: {
Expand Down Expand Up @@ -80,6 +81,7 @@ module.exports = {
can_duplicate: true,
can_move: true,
can_manage_access: true,
can_manage_tags: true,
can_delete: true,
},
user_partition_info: {
Expand Down
Loading

0 comments on commit 20af604

Please sign in to comment.