From 2932d989766a984e86cac2bc07b26d1a28cf2623 Mon Sep 17 00:00:00 2001
From: connorhaugh <49422820+connorhaugh@users.noreply.github.com>
Date: Tue, 21 Sep 2021 15:39:52 -0400
Subject: [PATCH] feat: breadcrumb rolloutout flag + analytics (#647)
As an addendum to https://openedx.atlassian.net/browse/TNL-7107, we want to hide rollout behind a frontend feature flag added in https://github.com/edx/edx-internal/pull/5489. We also want to report these events to the events api with name `edx.ui.lms.jump_nav.selected`. Doummentation to add this event is listed at the following PR: https://github.com/edx/edx-documentation/pull/1982
---
.env | 1 +
.env.development | 1 +
.env.test | 1 +
README.rst | 6 +
src/courseware/course/Course.test.jsx | 25 ++++
src/courseware/course/CourseBreadcrumbs.jsx | 39 ++++--
.../course/CourseBreadcrumbs.test.jsx | 117 ++++++++++++++++++
src/index.jsx | 1 +
8 files changed, 181 insertions(+), 10 deletions(-)
create mode 100644 src/courseware/course/CourseBreadcrumbs.test.jsx
diff --git a/.env b/.env
index a8f64ec2..8864ad88 100644
--- a/.env
+++ b/.env
@@ -37,3 +37,4 @@ TWITTER_HASHTAG=''
TWITTER_URL=''
USER_INFO_COOKIE_NAME=''
SESSION_COOKIE_DOMAIN=''
+ENABLE_JUMPNAV='true'
diff --git a/.env.development b/.env.development
index 3404a922..61164b00 100644
--- a/.env.development
+++ b/.env.development
@@ -37,3 +37,4 @@ TWITTER_HASHTAG='myedxjourney'
TWITTER_URL='https://twitter.com/edXOnline'
USER_INFO_COOKIE_NAME='edx-user-info'
SESSION_COOKIE_DOMAIN='localhost'
+ENABLE_JUMPNAV='true'
diff --git a/.env.test b/.env.test
index 4a1445bb..3b844f3c 100644
--- a/.env.test
+++ b/.env.test
@@ -36,3 +36,4 @@ TERMS_OF_SERVICE_URL='https://www.edx.org/edx-terms-service'
TWITTER_HASHTAG='myedxjourney'
TWITTER_URL='https://twitter.com/edXOnline'
USER_INFO_COOKIE_NAME='edx-user-info'
+ENABLE_JUMPNAV='true'
diff --git a/README.rst b/README.rst
index b19b4d00..4af4a220 100644
--- a/README.rst
+++ b/README.rst
@@ -109,3 +109,9 @@ TWITTER_URL
unless this is set. Optional.
Example: https://twitter.com/edXOnline
+
+ENABLE_JUMPNAV
+ Enables the new Jump Navigation feature in the course breadcrumbs, defaulted to the string 'true'.
+ Disable to have simple hyperlinks for breadcrumbs. Setting it to any other value but 'true' ('false','I love flags', 'etc' would disable the Jumpnav).
+ This feature flag is slated to be removed as jumpnav becomes default. Follow the progress of this ticket here:
+ https://openedx.atlassian.net/browse/TNL-8678
diff --git a/src/courseware/course/Course.test.jsx b/src/courseware/course/Course.test.jsx
index ea454d23..26512c86 100644
--- a/src/courseware/course/Course.test.jsx
+++ b/src/courseware/course/Course.test.jsx
@@ -91,6 +91,31 @@ describe('Course', () => {
expect(notificationTrigger).not.toHaveClass('trigger-active');
});
+ it('renders course breadcrumbs as expected', async () => {
+ const courseMetadata = Factory.build('courseMetadata');
+ const unitBlocks = Array.from({ length: 3 }).map(() => Factory.build(
+ 'block',
+ { type: 'vertical' },
+ { courseId: courseMetadata.id },
+ ));
+ const testStore = await initializeTestStore({ courseMetadata, unitBlocks }, false);
+ const { courseware, models } = testStore.getState();
+ const { courseId, sequenceId } = courseware;
+ const testData = {
+ ...mockData,
+ courseId,
+ sequenceId,
+ unitId: Object.values(models.units)[1].id, // Corner cases are already covered in `Sequence` tests.
+ };
+ render(, { store: testStore });
+
+ loadUnit();
+ await waitFor(() => expect(screen.queryByText('Loading learning sequence...')).not.toBeInTheDocument());
+ // expect the section and sequence "titles" to be loaded in as breadcrumb labels.
+ expect(screen.getByText('cdabcdabcdabcdabcdabcdabcdabcd13')).toBeInTheDocument();
+ expect(screen.getByText('cdabcdabcdabcdabcdabcdabcdabcd12')).toBeInTheDocument();
+ });
+
it('passes handlers to the sequence', async () => {
const nextSequenceHandler = jest.fn();
const previousSequenceHandler = jest.fn();
diff --git a/src/courseware/course/CourseBreadcrumbs.jsx b/src/courseware/course/CourseBreadcrumbs.jsx
index e6b4e85b..7b918bb0 100644
--- a/src/courseware/course/CourseBreadcrumbs.jsx
+++ b/src/courseware/course/CourseBreadcrumbs.jsx
@@ -7,6 +7,10 @@ import { faHome } from '@fortawesome/free-solid-svg-icons';
import { useSelector } from 'react-redux';
import { Hyperlink, MenuItem, SelectMenu } from '@edx/paragon';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
+import {
+ sendTrackingLogEvent,
+ sendTrackEvent,
+} from '@edx/frontend-platform/analytics';
import { useModel, useModels } from '../../generic/model-store';
/** [MM-P2P] Experiment */
import { MMP2PFlyoverTrigger } from '../../experiments/mm-p2p';
@@ -16,14 +20,31 @@ function CourseBreadcrumb({
}) {
const defaultContent = content.filter(destination => destination.default)[0];
const { administrator } = getAuthenticatedUser();
+ function logEvent(target) {
+ const eventName = 'edx.ui.lms.jump_nav.selected';
+ const payload = {
+ target_name: target.label,
+ id: target.id,
+ current_id: defaultContent.id,
+ widget_placement: 'breadcrumb',
+ };
+ sendTrackEvent(eventName, payload);
+ sendTrackingLogEvent(eventName, payload);
+ }
return (
<>
{withSeparator && (
-
/
+ /
)}
-
- {process.env.NODE_ENV !== 'test' || content.length < 2 || !administrator
+
+
+ { getConfig().ENABLE_JUMPNAV !== 'true' || content.length < 2 || !administrator
? (
{defaultContent.label}
@@ -34,7 +55,8 @@ function CourseBreadcrumb({
@@ -46,7 +68,6 @@ function CourseBreadcrumb({
>
);
}
-
CourseBreadcrumb.propTypes = {
content: PropTypes.arrayOf(
PropTypes.shape({
@@ -72,7 +93,7 @@ export default function CourseBreadcrumbs({
}) {
const course = useModel('coursewareMeta', courseId);
const courseStatus = useSelector(state => state.courseware.courseStatus);
- const sections = Object.fromEntries(useModels('sections', course.sectionIds).map(section => [section.id, section]));
+ const sections = course ? Object.fromEntries(useModels('sections', course.sectionIds).map(section => [section.id, section])) : null;
const possibleSequences = sections && sectionId ? sections[sectionId].sequenceIds : [];
const sequences = Object.fromEntries(useModels('sequences', possibleSequences).map(sequence => [sequence.id, sequence]));
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
@@ -97,13 +118,12 @@ export default function CourseBreadcrumbs({
}
return temp;
}, [courseStatus, sections, sequences]);
-
return (