Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: wrap existing sidebars in frontend-plugin-framework PluginSlots #1543

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions src/courseware/course/Course.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@ import { breakpoints, useWindowSize } from '@openedx/paragon';
import { AlertList } from '@src/generic/user-messages';
import { useModel } from '@src/generic/model-store';
import { getCoursewareOutlineSidebarSettings } from '../data/selectors';
import { Trigger as CourseOutlineTrigger } from './sidebar/sidebars/course-outline';
import Chat from './chat/Chat';
import SidebarProvider from './sidebar/SidebarContextProvider';
import SidebarTriggers from './sidebar/SidebarTriggers';
import NewSidebarProvider from './new-sidebar/SidebarContextProvider';
import NewSidebarTriggers from './new-sidebar/SidebarTriggers';
import { NotificationsDiscussionsSidebarTriggerSlot } from '../../plugin-slots/NotificationsDiscussionsSidebarTriggerSlot';
import { CelebrationModal, shouldCelebrateOnSectionLoad, WeeklyGoalCelebrationModal } from './celebration';
import CourseBreadcrumbs from './CourseBreadcrumbs';
import ContentTools from './content-tools';
import Sequence from './sequence';
import { CourseOutlineMobileSidebarTriggerSlot } from '../../plugin-slots/CourseOutlineMobileSidebarTriggerSlot';
import { CourseBreadcrumbsSlot } from '../../plugin-slots/CourseBreadcrumbsSlot';

const Course = ({
courseId,
Expand Down Expand Up @@ -87,7 +86,7 @@ const Course = ({
<div className="position-relative d-flex align-items-xl-center mb-4 mt-1 flex-column flex-xl-row">
{navigationDisabled || (
<>
<CourseBreadcrumbs
<CourseBreadcrumbsSlot
courseId={courseId}
sectionId={section ? section.id : null}
sequenceId={sequenceId}
Expand All @@ -109,8 +108,8 @@ const Course = ({
</>
)}
<div className="w-100 d-flex align-items-center">
<CourseOutlineTrigger isMobileView />
{isNewDiscussionSidebarViewEnabled ? <NewSidebarTriggers /> : <SidebarTriggers /> }
<CourseOutlineMobileSidebarTriggerSlot />
<NotificationsDiscussionsSidebarTriggerSlot courseId={courseId} />
</div>
</div>

Expand Down
16 changes: 6 additions & 10 deletions src/courseware/course/sequence/Sequence.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@ import SequenceContainerSlot from '../../../plugin-slots/SequenceContainerSlot';

import { getCoursewareOutlineSidebarSettings } from '../../data/selectors';
import CourseLicense from '../course-license';
import Sidebar from '../sidebar/Sidebar';
import NewSidebar from '../new-sidebar/Sidebar';
import {
Trigger as CourseOutlineTrigger,
Sidebar as CourseOutlineTray,
} from '../sidebar/sidebars/course-outline';
import { NotificationsDiscussionsSidebarSlot } from '../../../plugin-slots/NotificationsDiscussionsSidebarSlot';
import messages from './messages';
import HiddenAfterDue from './hidden-after-due';
import { SequenceNavigation, UnitNavigation } from './sequence-navigation';
import SequenceContent from './SequenceContent';
import { CourseOutlineSidebarSlot } from '../../../plugin-slots/CourseOutlineSidebarSlot';
import { CourseOutlineSidebarTriggerSlot } from '../../../plugin-slots/CourseOutlineSidebarTriggerSlot';

const Sequence = ({
unitId,
Expand All @@ -46,7 +43,6 @@ const Sequence = ({
const {
isStaff,
originalUserIsStaff,
isNewDiscussionSidebarViewEnabled,
} = useModel('courseHomeMeta', courseId);
const sequence = useModel('sequences', sequenceId);
const unit = useModel('units', unitId);
Expand Down Expand Up @@ -166,8 +162,8 @@ const Sequence = ({
const defaultContent = (
<>
<div className="sequence-container d-inline-flex flex-row w-100">
<CourseOutlineTrigger />
<CourseOutlineTray />
<CourseOutlineSidebarTriggerSlot />
<CourseOutlineSidebarSlot />
<div className="sequence w-100">
{!isEnabledOutlineSidebar && (
<div className="sequence-navigation-container">
Expand Down Expand Up @@ -209,7 +205,7 @@ const Sequence = ({
{unitHasLoaded && renderUnitNavigation(false)}
</div>
</div>
{isNewDiscussionSidebarViewEnabled ? <NewSidebar /> : <Sidebar />}
<NotificationsDiscussionsSidebarSlot courseId={courseId} />
</div>
<SequenceContainerSlot courseId={courseId} unitId={unitId} />
</>
Expand Down
43 changes: 43 additions & 0 deletions src/plugin-slots/CourseBreadcrumbsSlot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Course Breadcrumbs Slot

### Slot ID: `course_breadcrumbs_slot`

## Description

This slot is used to replace/modify/hide the course breadcrumbs.

## Example

### Default content
![Breadcrumbs slot with default content](./screenshot_default.png)

### Replaced with custom component
![🍞 in breadcrumbs slot](./screenshot_custom.png)

The following `env.config.jsx` will replace the course breadcrumbs entirely.

```js
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
course_breadcrumbs_slot: {
keepDefault: false,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_breadcrumbs_component',
type: DIRECT_PLUGIN,
RenderWidget: () => (
<h1>🍞</h1>
),
},
},
]
}
},
}

export default config;
```
32 changes: 32 additions & 0 deletions src/plugin-slots/CourseBreadcrumbsSlot/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';

import { PluginSlot } from '@openedx/frontend-plugin-framework';

import CourseBreadcrumbs from '../../courseware/course/CourseBreadcrumbs';

interface Props {
courseId: string;
sectionId?: string;
sequenceId?: string;
unitId?: string;
isStaff?: boolean;
}

export const CourseBreadcrumbsSlot : React.FC<Props> = ({
courseId, sectionId, sequenceId, unitId, isStaff,
}) => (
<PluginSlot
id="course_breadcrumbs_slot"
slotOptions={{
mergeProps: true,
}}
>
<CourseBreadcrumbs
courseId={courseId}
sectionId={sectionId}
sequenceId={sequenceId}
isStaff={isStaff}
unitId={unitId}
/>
</PluginSlot>
);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions src/plugin-slots/CourseOutlineMobileSidebarTriggerSlot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Course Outline Mobile Sidebar Trigger Slot

### Slot ID: `course_outline_mobile_sidebar_trigger_slot`

## Description

This slot is used to replace/modify/hide the course outline sidebar mobile trigger.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what is the "course outline sidebar mobile trigger"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ties in to the "wrapping complexity" goal of this PR. The course outline sidebar trigger (the button that opens up the sidebar) is displayed in a different location (both visually and within the DOM) on mobile vs on desktop. The CourseOutlineTrigger component is used in both Sequence and Course. In Course, the component is used with isMobileView always set to true, where as in Sequence it is always set to false.

With the new slots, CourseOutlineMobileSidebarTriggerSlot exists only in Course, and CourseOutlineSidebarTriggerSlot exists only in Sequence.

I'm not sure what the best way to communicate this complexity in the README would be, any suggestions are very warmly welcome!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I do think it's more clear with the updated README screenshots showing before+after! Otherwise I don't have any suggestions :/


## Example

### Default content
![Trigger slot with default content](./screenshot_default.png)

### Replaced with custom component
![📌 in trigger slot](./screenshot_custom.png)

The following `env.config.jsx` will replace the course outline sidebar mobile trigger entirely.

```js
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
course_outline_mobile_sidebar_trigger_slot: {
keepDefault: false,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_sidebar_trigger_component',
type: DIRECT_PLUGIN,
RenderWidget: () => (
<h1 className="d-xl-none">📌</h1>
),
},
},
]
}
},
}

export default config;
```
16 changes: 16 additions & 0 deletions src/plugin-slots/CourseOutlineMobileSidebarTriggerSlot/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';

import { PluginSlot } from '@openedx/frontend-plugin-framework';

import CourseOutlineTrigger from '../../courseware/course/sidebar/sidebars/course-outline/CourseOutlineTrigger';

export const CourseOutlineMobileSidebarTriggerSlot : React.FC = () => (
<PluginSlot
id="course_outline_mobile_sidebar_trigger_slot"
slotOptions={{
mergeProps: true,
}}
>
<CourseOutlineTrigger isMobileView />
</PluginSlot>
);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions src/plugin-slots/CourseOutlineSidebarSlot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Course Outline Sidebar Slot

### Slot ID: `course_outline_sidebar_slot`

## Description

This slot is used to replace/modify/hide the course outline sidebar.
bradenmacdonald marked this conversation as resolved.
Show resolved Hide resolved

## Example

### Default content
![Sidebar slot with default content](./screenshot_default.png)

### Replaced with custom component
![📊 in sidebar slot](./screenshot_custom.png)

The following `env.config.jsx` will replace the course outline sidebar entirely.

```js
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
course_outline_sidebar_slot: {
keepDefault: false,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_sidebar_component',
type: DIRECT_PLUGIN,
RenderWidget: () => (
<h1>📊</h1>
),
},
},
]
}
},
}

export default config;
```
16 changes: 16 additions & 0 deletions src/plugin-slots/CourseOutlineSidebarSlot/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';

import { PluginSlot } from '@openedx/frontend-plugin-framework';

import CourseOutlineTray from '../../courseware/course/sidebar/sidebars/course-outline/CourseOutlineTray';

export const CourseOutlineSidebarSlot : React.FC = () => (
<PluginSlot
id="course_outline_sidebar_slot"
slotOptions={{
mergeProps: true,
}}
>
<CourseOutlineTray />
</PluginSlot>
);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions src/plugin-slots/CourseOutlineSidebarTriggerSlot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Course Outline Sidebar Trigger Slot

### Slot ID: `course_outline_sidebar_trigger_slot`

## Description

This slot is used to replace/modify/hide the course outline sidebar trigger.

## Example

### Default content
![Trigger slot with default content](./screenshot_default.png)

### Replaced with custom component
![📌 in trigger slot](./screenshot_custom.png)

The following `env.config.jsx` will replace the course outline sidebar trigger entirely.

```js
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
course_outline_sidebar_trigger_slot: {
keepDefault: false,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_sidebar_trigger_component',
type: DIRECT_PLUGIN,
RenderWidget: () => (
<h1 className="d-none d-xl-block">📌</h1>
),
},
},
]
}
},
}

export default config;
```
16 changes: 16 additions & 0 deletions src/plugin-slots/CourseOutlineSidebarTriggerSlot/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';

import { PluginSlot } from '@openedx/frontend-plugin-framework';

import CourseOutlineTrigger from '../../courseware/course/sidebar/sidebars/course-outline/CourseOutlineTrigger';

export const CourseOutlineSidebarTriggerSlot : React.FC = () => (
<PluginSlot
id="course_outline_sidebar_trigger_slot"
slotOptions={{
mergeProps: true,
}}
>
<CourseOutlineTrigger isMobileView={false} />
</PluginSlot>
);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions src/plugin-slots/NotificationsDiscussionsSidebarSlot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Notifications Discussions Sidebar Slot

### Slot ID: `notifications_discussions_sidebar_slot`

## Description

This slot is used to replace/modify/hide the notifications discussions sidebar.

## Example

### Default content
![Sidebar slot with default content](./screenshot_default.png)

### Replaced with custom component
![📊 in sidebar slot](./screenshot_custom.png)

The following `env.config.jsx` will replace the notifications discussions sidebar.

```js
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
notifications_discussions_sidebar_slot: {
keepDefault: false,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_sidebar_component',
type: DIRECT_PLUGIN,
RenderWidget: () => (
<h1>📊</h1>
),
},
},
]
}
},
}

export default config;
```
Loading
Loading