feat: add v2 CourseAuthoringUnitSidebarSlot (#2000)

This commit is contained in:
Arunmozhi
2025-06-11 01:46:27 +10:00
committed by GitHub
parent 0e2cab2838
commit 73ac6d725a
4 changed files with 148 additions and 40 deletions

View File

@@ -3,8 +3,7 @@ import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
import {
Container, Layout, Stack, Button, TransitionReplace,
Alert,
Alert, Container, Layout, Button, TransitionReplace,
} from '@openedx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
@@ -27,8 +26,6 @@ import AddComponent from './add-component/AddComponent';
import HeaderTitle from './header-title/HeaderTitle';
import Breadcrumbs from './breadcrumbs/Breadcrumbs';
import Sequence from './course-sequence';
import Sidebar from './sidebar';
import SplitTestSidebarInfo from './sidebar/SplitTestSidebarInfo';
import { useCourseUnit, useLayoutGrid, useScrollToLastPosition } from './hooks';
import messages from './messages';
import { PasteNotificationAlert } from './clipboard';
@@ -244,22 +241,15 @@ const CourseUnit = ({ courseId }) => {
<IframePreviewLibraryXBlockChanges />
</Layout.Element>
<Layout.Element>
<Stack gap={3}>
{isUnitVerticalType && (
<CourseAuthoringUnitSidebarSlot
courseId={courseId}
blockId={blockId}
unitTitle={unitTitle}
xBlocks={courseVerticalChildren.children}
readOnly={readOnly}
/>
)}
{isSplitTestType && (
<Sidebar data-testid="course-split-test-sidebar">
<SplitTestSidebarInfo />
</Sidebar>
)}
</Stack>
<CourseAuthoringUnitSidebarSlot
courseId={courseId}
blockId={blockId}
unitTitle={unitTitle}
xBlocks={courseVerticalChildren.children}
readOnly={readOnly}
isUnitVerticalType={isUnitVerticalType}
isSplitTestType={isSplitTestType}
/>
</Layout.Element>
</Layout>
</section>

View File

@@ -1,9 +1,8 @@
# CourseAuthoringUnitSidebarSlot
### Slot ID: `org.openedx.frontend.authoring.course_unit_sidebar.v1`
### Slot ID: `org.openedx.frontend.authoring.course_unit_sidebar.v2`
### Slot ID Aliases
* `course_authoring_unit_sidebar_slot`
### Previous Version: [`org.openedx.frontend.authoring.course_unit_sidebar.v1`](./README.v1.md)
### Plugin Props:
@@ -12,6 +11,8 @@
* `unitTitle` - String. The name of the current unit being viewed / edited.
* `xBlocks` - Array of Objects. List of XBlocks in the Unit. Object structure defined in `index.tsx`.
* `readOnly` - Boolean. True if the user should not be able to edit the contents of the unit.
* `isUnitVerticalType` - Boolean. If the unit category is `vertical`.
* `isSplitTestType` - Boolean. If the unit category is `split_test`.
## Description
@@ -29,7 +30,7 @@ import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
const config = {
pluginSlots: {
'org.openedx.frontend.authoring.course_unit_sidebar.v1': {
'org.openedx.frontend.authoring.course_unit_sidebar.v2': {
keepDefault: true,
plugins: [
{
@@ -63,11 +64,11 @@ const ProblemBlocks = ({unitTitle, xBlocks}) => (
}
</ul>
</>
);
);
const config = {
pluginSlots: {
'org.openedx.frontend.authoring.course_unit_sidebar.v1': {
'org.openedx.frontend.authoring.course_unit_sidebar.v2': {
keepDefault: true,
plugins: [
{

View File

@@ -0,0 +1,95 @@
# CourseAuthoringUnitSidebarSlot
### Slot ID: `org.openedx.frontend.authoring.course_unit_sidebar.v1`
### Slot ID Aliases: `course_authoring_unit_sidebar_slot`
### Plugin Props:
* `courseId` - String.
* `blockId` - String. The usage id of the current unit being viewed / edited.
* `unitTitle` - String. The name of the current unit being viewed / edited.
* `xBlocks` - Array of Objects. List of XBlocks in the Unit. Object structure defined in `index.tsx`.
* `readOnly` - Boolean. True if the user should not be able to edit the contents of the unit.
### Description
The slot wraps the sidebar that is displayed on the unit editor page. It can
be used to add additional sidebar components or modify the existing sidebar.
> [!IMPORTANT]
> This document describes an older version `v1` of the `CourseAuthoringUnitSidebarSlot`.
> It is recommended to use the `org.openedx.frontend.authoring.course_unit_sidebar.v2` slot ID for new plugins.
The `v1` slot has the following limitations compared to the `v2` version:
* It renders conditionally based on the `isUnitVerticalType` prop, which means the plugins won't be rendered in other scenarios like unit with library blocks.
* It does **not** wrap the `SplitTestSidebarInfo` component. So it can't be hidden from the sidebar by overriding the components in the slot.
* As it is not the primary child component of the sidebar, CSS styling for inserted components face limitations, such as an inability to be `sticky` or achieve 100% height.
## Example 1
![Screenshot of the unit sidebar surrounded by border](./images/unit_sidebar_with_border.png)
The following example configuration surrounds the sidebar in a border as shown above.
```js
import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
const config = {
pluginSlots: {
'org.openedx.frontend.authoring.course_unit_sidebar.v1': {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Wrap,
widgetId: 'default_contents',
wrapper: ({ component }) => (
<div style={{ border: 'thick dashed red' }}>{component}</div>
),
},
],
},
}
};
export default config;
```
## Example 2
![Screenshot of the unit sidebar with an extra component listing all the problem blocks](./images/unit_sidebar_with_problem_blocks_list.png)
```js
import { PLUGIN_OPERATIONS, DIRECT_PLUGIN } from '@openedx/frontend-plugin-framework';
const ProblemBlocks = ({unitTitle, xBlocks}) => (
<>
<h4 className="h4">{unitTitle}: Problem Blocks</h4>
<ul>
{xBlocks
.filter(block => block.blockType === "problem")
.map(block => <li key={block.id}>{block.displayName}</li>)
}
</ul>
</>
);
const config = {
pluginSlots: {
'org.openedx.frontend.authoring.course_unit_sidebar.v1': {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget:{
id: 'problem-blocks-list',
priority: 1,
type: DIRECT_PLUGIN,
RenderWidget: ProblemBlocks,
}
},
],
},
}
};
export default config;
```

View File

@@ -1,9 +1,11 @@
import { getConfig } from '@edx/frontend-platform';
import { PluginSlot } from '@openedx/frontend-plugin-framework/dist';
import { Stack } from '@openedx/paragon';
import TagsSidebarControls from '../../content-tags-drawer/tags-sidebar-controls';
import Sidebar from '../../course-unit/sidebar';
import LocationInfo from '../../course-unit/sidebar/LocationInfo';
import PublishControls from '../../course-unit/sidebar/PublishControls';
import SplitTestSidebarInfo from '../../course-unit/sidebar/SplitTestSidebarInfo';
export const CourseAuthoringUnitSidebarSlot = (
{
@@ -12,26 +14,44 @@ export const CourseAuthoringUnitSidebarSlot = (
unitTitle,
xBlocks,
readOnly,
isUnitVerticalType,
isSplitTestType,
}: CourseAuthoringUnitSidebarSlotProps,
) => (
<PluginSlot
id="org.openedx.frontend.authoring.course_unit_sidebar.v1"
idAliases={['course_authoring_unit_sidebar_slot']}
id="org.openedx.frontend.authoring.course_unit_sidebar.v2"
pluginProps={{
blockId, courseId, unitTitle, xBlocks, readOnly,
blockId, courseId, unitTitle, xBlocks, readOnly, isUnitVerticalType, isSplitTestType,
}}
>
<Sidebar data-testid="course-unit-sidebar">
<PublishControls blockId={blockId} />
</Sidebar>
{getConfig().ENABLE_TAGGING_TAXONOMY_PAGES === 'true' && (
<Sidebar className="tags-sidebar">
<TagsSidebarControls readOnly={readOnly} />
</Sidebar>
)}
<Sidebar data-testid="course-unit-location-sidebar">
<LocationInfo />
</Sidebar>
<Stack gap={3}>
{isUnitVerticalType && (
<PluginSlot
id="org.openedx.frontend.authoring.course_unit_sidebar.v1"
idAliases={['course_authoring_unit_sidebar_slot']}
pluginProps={{
blockId, courseId, unitTitle, xBlocks, readOnly,
}}
>
<Sidebar data-testid="course-unit-sidebar">
<PublishControls blockId={blockId} />
</Sidebar>
{getConfig().ENABLE_TAGGING_TAXONOMY_PAGES === 'true' && (
<Sidebar className="tags-sidebar">
<TagsSidebarControls readOnly={readOnly} />
</Sidebar>
)}
<Sidebar data-testid="course-unit-location-sidebar">
<LocationInfo />
</Sidebar>
</PluginSlot>
)}
{isSplitTestType && (
<Sidebar data-testid="course-split-test-sidebar">
<SplitTestSidebarInfo />
</Sidebar>
)}
</Stack>
</PluginSlot>
);
@@ -47,4 +67,6 @@ interface CourseAuthoringUnitSidebarSlotProps {
unitTitle: string;
xBlocks: XBlock[];
readOnly: boolean;
isUnitVerticalType: boolean;
isSplitTestType: boolean;
}