feat: Add plugin slots for sidebars (#1752)

This commit is contained in:
Kshitij Sobti
2025-04-11 16:49:13 +05:30
committed by GitHub
parent 5df7adffec
commit 341a03c50b
12 changed files with 168 additions and 50 deletions

View File

@@ -22,6 +22,7 @@ import {
verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { useLocation } from 'react-router-dom';
import { CourseAuthoringOutlineSidebarSlot } from '../plugin-slots/CourseAuthoringOutlineSidebarSlot';
import { LoadingSpinner } from '../generic/Loading';
import { getProcessingNotification } from '../generic/processing-notification/data/selectors';
@@ -35,7 +36,6 @@ import AlertMessage from '../generic/alert-message';
import getPageHeadTitle from '../generic/utils';
import { getCurrentItem, getProctoredExamsFlag } from './data/selectors';
import { COURSE_BLOCK_NAMES } from './constants';
import OutlineSideBar from './outline-sidebar/OutlineSidebar';
import StatusBar from './status-bar/StatusBar';
import EnableHighlightsModal from './enable-highlights-modal/EnableHighlightsModal';
import SectionCard from './section-card/SectionCard';
@@ -453,7 +453,7 @@ const CourseOutline = ({ courseId }) => {
</article>
</Layout.Element>
<Layout.Element>
<OutlineSideBar courseId={courseId} />
<CourseAuthoringOutlineSidebarSlot courseId={courseId} />
</Layout.Element>
</Layout>
<EnableHighlightsModal

View File

@@ -26,7 +26,6 @@ const OutlineSideBar = ({ courseId }) => {
return (
<HelpSidebar
intl={intl}
courseId={courseId}
showOtherSettings={false}
className="outline-sidebar mt-4"

View File

@@ -5,12 +5,12 @@ import { useParams } from 'react-router-dom';
import {
Container, Layout, Stack, Button, TransitionReplace,
} from '@openedx/paragon';
import { getConfig } from '@edx/frontend-platform';
import { useIntl, injectIntl } from '@edx/frontend-platform/i18n';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Warning as WarningIcon,
CheckCircle as CheckCircleIcon,
} from '@openedx/paragon/icons';
import { CourseAuthoringUnitSidebarSlot } from '../plugin-slots/CourseAuthoringUnitSidebarSlot';
import { getProcessingNotification } from '../generic/processing-notification/data/selectors';
import SubHeader from '../generic/sub-header/SubHeader';
@@ -30,9 +30,6 @@ import Sidebar from './sidebar';
import SplitTestSidebarInfo from './sidebar/SplitTestSidebarInfo';
import { useCourseUnit, useLayoutGrid, useScrollToLastPosition } from './hooks';
import messages from './messages';
import PublishControls from './sidebar/PublishControls';
import LocationInfo from './sidebar/LocationInfo';
import TagsSidebarControls from '../content-tags-drawer/tags-sidebar-controls';
import { PasteNotificationAlert } from './clipboard';
import XBlockContainerIframe from './xblock-container-iframe';
import MoveModal from './move-modal';
@@ -225,19 +222,11 @@ const CourseUnit = ({ courseId }) => {
<Layout.Element>
<Stack gap={3}>
{isUnitVerticalType && (
<>
<Sidebar data-testid="course-unit-sidebar">
<PublishControls blockId={blockId} />
</Sidebar>
{getConfig().ENABLE_TAGGING_TAXONOMY_PAGES === 'true' && (
<Sidebar className="tags-sidebar">
<TagsSidebarControls />
</Sidebar>
)}
<Sidebar data-testid="course-unit-location-sidebar">
<LocationInfo />
</Sidebar>
</>
<CourseAuthoringUnitSidebarSlot
courseId={courseId}
blockId={blockId}
unitTitle={unitTitle}
/>
)}
{isSplitTestType && (
<Sidebar data-testid="course-split-test-sidebar">
@@ -267,4 +256,4 @@ CourseUnit.propTypes = {
courseId: PropTypes.string.isRequired,
};
export default injectIntl(CourseUnit);
export default CourseUnit;

View File

@@ -1,24 +0,0 @@
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Card } from '@openedx/paragon';
const Sidebar = ({ className, children, ...props }) => (
<Card
className={classNames('course-unit-sidebar', className)}
{...props}
>
{children}
</Card>
);
Sidebar.propTypes = {
className: PropTypes.string,
children: PropTypes.node,
};
Sidebar.defaultProps = {
className: null,
children: null,
};
export default Sidebar;

View File

@@ -0,0 +1,18 @@
import classNames from 'classnames';
import { Card } from '@openedx/paragon';
const Sidebar = ({ className = null, children = null, ...props }:SidebarProps) => (
<Card
className={classNames('course-unit-sidebar', className)}
{...props}
>
{children}
</Card>
);
interface SidebarProps {
className?: string | null;
children?: React.ReactNode | null;
}
export default Sidebar;

View File

@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import classNames from 'classnames';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { useIntl } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
import { getWaffleFlags } from '../../data/selectors';
@@ -11,13 +11,13 @@ import messages from './messages';
import HelpSidebarLink from './HelpSidebarLink';
const HelpSidebar = ({
intl,
courseId,
showOtherSettings,
proctoredExamSettingsUrl,
children,
className,
}) => {
const intl = useIntl();
const { pathname } = useLocation();
const {
grading,
@@ -124,7 +124,6 @@ HelpSidebar.defaultProps = {
};
HelpSidebar.propTypes = {
intl: intlShape.isRequired,
courseId: PropTypes.string,
showOtherSettings: PropTypes.bool,
proctoredExamSettingsUrl: PropTypes.string,
@@ -132,4 +131,4 @@ HelpSidebar.propTypes = {
className: PropTypes.string,
};
export default injectIntl(HelpSidebar);
export default HelpSidebar;

View File

@@ -0,0 +1,40 @@
# CourseAuthoringOutlineSidebarSlot
### Slot ID: `course_authoring_outline_sidebar_slot`
### Plugin Props:
* `courseId` - String.
## Description
The slot wraps the sidebar that is displayed on the course outline page. It can
be used to add additional sidebar components or modify the existing sidebar.
## Example
![Screenshot of the outline sidebar surrounded by border](./images/outline_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: {
course_authoring_outline_sidebar_slot: {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Wrap,
widgetId: 'default_contents',
wrapper: ({ component }) => (
<div style={{ border: 'thick dashed red' }}>{component}</div>
),
},
],
},
}
};
export default config;
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@@ -0,0 +1,18 @@
import { PluginSlot } from '@openedx/frontend-plugin-framework/dist';
import React from 'react';
import OutlineSideBar from '../../course-outline/outline-sidebar/OutlineSidebar';
export const CourseAuthoringOutlineSidebarSlot = ({ courseId }: CourseAuthoringOutlineSidebarSlotProps) => (
<PluginSlot
id="course_authoring_outline_sidebar_slot"
pluginProps={{
courseId,
}}
>
<OutlineSideBar courseId={courseId} />
</PluginSlot>
);
interface CourseAuthoringOutlineSidebarSlotProps {
courseId: string;
}

View File

@@ -0,0 +1,42 @@
# CourseAuthoringUnitSidebarSlot
### Slot ID: `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.
## 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.
## Example
![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: {
course_authoring_unit_sidebar_slot: {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Wrap,
widgetId: 'default_contents',
wrapper: ({ component }) => (
<div style={{ border: 'thick dashed red' }}>{component}</div>
),
},
],
},
}
};
export default config;
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

View File

@@ -0,0 +1,37 @@
import { getConfig } from '@edx/frontend-platform';
import { PluginSlot } from '@openedx/frontend-plugin-framework/dist';
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';
export const CourseAuthoringUnitSidebarSlot = (
{
blockId,
courseId,
unitTitle,
}: CourseAuthoringUnitSidebarSlotProps,
) => (
<PluginSlot
id="course_authoring_unit_sidebar_slot"
pluginProps={{ blockId, courseId, unitTitle }}
>
<Sidebar data-testid="course-unit-sidebar">
<PublishControls blockId={blockId} />
</Sidebar>
{getConfig().ENABLE_TAGGING_TAXONOMY_PAGES === 'true' && (
<Sidebar className="tags-sidebar">
<TagsSidebarControls />
</Sidebar>
)}
<Sidebar data-testid="course-unit-location-sidebar">
<LocationInfo />
</Sidebar>
</PluginSlot>
);
interface CourseAuthoringUnitSidebarSlotProps {
blockId: string;
courseId: string;
unitTitle: string;
}