feat: Add plugin slots for sidebars (#1752)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -26,7 +26,6 @@ const OutlineSideBar = ({ courseId }) => {
|
||||
|
||||
return (
|
||||
<HelpSidebar
|
||||
intl={intl}
|
||||
courseId={courseId}
|
||||
showOtherSettings={false}
|
||||
className="outline-sidebar mt-4"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
18
src/course-unit/sidebar/index.tsx
Normal file
18
src/course-unit/sidebar/index.tsx
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
40
src/plugin-slots/CourseAuthoringOutlineSidebarSlot/README.md
Normal file
40
src/plugin-slots/CourseAuthoringOutlineSidebarSlot/README.md
Normal 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
|
||||
|
||||

|
||||
|
||||
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 |
18
src/plugin-slots/CourseAuthoringOutlineSidebarSlot/index.tsx
Normal file
18
src/plugin-slots/CourseAuthoringOutlineSidebarSlot/index.tsx
Normal 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;
|
||||
}
|
||||
42
src/plugin-slots/CourseAuthoringUnitSidebarSlot/README.md
Normal file
42
src/plugin-slots/CourseAuthoringUnitSidebarSlot/README.md
Normal 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
|
||||
|
||||

|
||||
|
||||
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 |
37
src/plugin-slots/CourseAuthoringUnitSidebarSlot/index.tsx
Normal file
37
src/plugin-slots/CourseAuthoringUnitSidebarSlot/index.tsx
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user