-
Notifications
You must be signed in to change notification settings - Fork 149
feat: show sync button on section/subsections [FC-0097] #2324
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
Changes from 6 commits
515f9b1
ac58188
3b25a68
08afd0d
da252f1
6ebf564
46dc4ca
b47249c
942b25d
e2971f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { type QueryClient } from '@tanstack/react-query'; | ||
import { courseLibrariesQueryKeys } from './data/apiHooks'; | ||
|
||
/** | ||
* Ivalidates the downstream links query for a course | ||
*/ | ||
export const invalidateLinksQuery = (queryClient: QueryClient, courseId: string) => { | ||
queryClient.invalidateQueries({ | ||
queryKey: courseLibrariesQueryKeys.courseLibraries(courseId), | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import { | ||
useContext, useEffect, useState, useRef, useCallback, ReactNode, | ||
useContext, useEffect, useState, useRef, useCallback, ReactNode, useMemo, | ||
} from 'react'; | ||
import { useDispatch } from 'react-redux'; | ||
import { useIntl } from '@edx/frontend-platform/i18n'; | ||
|
@@ -8,6 +8,7 @@ import { | |
} from '@openedx/paragon'; | ||
import { useSearchParams } from 'react-router-dom'; | ||
import classNames from 'classnames'; | ||
import { useQueryClient } from '@tanstack/react-query'; | ||
|
||
import { setCurrentItem, setCurrentSection } from '@src/course-outline/data/slice'; | ||
import { RequestStatus } from '@src/data/constants'; | ||
|
@@ -16,18 +17,22 @@ import SortableItem from '@src/course-outline/drag-helper/SortableItem'; | |
import { DragContext } from '@src/course-outline/drag-helper/DragContextProvider'; | ||
import TitleButton from '@src/course-outline/card-header/TitleButton'; | ||
import XBlockStatus from '@src/course-outline/xblock-status/XBlockStatus'; | ||
import { fetchCourseSectionQuery } from '@src/course-outline/data/thunk'; | ||
import { getItemStatus, getItemStatusBorder, scrollToElement } from '@src/course-outline/utils'; | ||
import OutlineAddChildButtons from '@src/course-outline/OutlineAddChildButtons'; | ||
import { ContainerType } from '@src/generic/key-utils'; | ||
import { ComponentPicker, SelectedComponent } from '@src/library-authoring'; | ||
import { ContentType } from '@src/library-authoring/routes'; | ||
import { COMPONENT_TYPES } from '@src/generic/block-type-utils/constants'; | ||
import { PreviewLibraryXBlockChanges } from '@src/course-unit/preview-changes'; | ||
import { UpstreamInfoIcon } from '@src/generic/upstream-info-icon'; | ||
import type { XBlock } from '@src/data/types'; | ||
import { invalidateLinksQuery } from '@src/course-libraries/utils'; | ||
import messages from './messages'; | ||
|
||
interface SectionCardProps { | ||
section: XBlock, | ||
courseId: string, | ||
isSelfPaced: boolean, | ||
isCustomRelativeDatesActive: boolean, | ||
children: ReactNode, | ||
|
@@ -49,6 +54,7 @@ interface SectionCardProps { | |
|
||
const SectionCard = ({ | ||
section, | ||
courseId, | ||
isSelfPaced, | ||
isCustomRelativeDatesActive, | ||
children, | ||
|
@@ -79,6 +85,7 @@ const SectionCard = ({ | |
openAddLibrarySubsectionModal, | ||
closeAddLibrarySubsectionModal, | ||
] = useToggle(false); | ||
const queryClient = useQueryClient(); | ||
|
||
// Expand the section if a search result should be shown/scrolled to | ||
const containsSearchResult = () => { | ||
|
@@ -107,6 +114,7 @@ const SectionCard = ({ | |
}; | ||
const [isExpanded, setIsExpanded] = useState(containsSearchResult() || isSectionsExpanded); | ||
const [isFormOpen, openForm, closeForm] = useToggle(false); | ||
const [isSyncModalOpen, openSyncModal, closeSyncModal] = useToggle(false); | ||
const namePrefix = 'section'; | ||
|
||
useEffect(() => { | ||
|
@@ -126,6 +134,19 @@ const SectionCard = ({ | |
upstreamInfo, | ||
} = section; | ||
|
||
const blockSyncData = useMemo(() => { | ||
if (!upstreamInfo?.readyToSync) { | ||
return undefined; | ||
} | ||
return { | ||
displayName, | ||
downstreamBlockId: id, | ||
upstreamBlockId: upstreamInfo.upstreamRef, | ||
upstreamBlockVersionSynced: upstreamInfo.versionSynced, | ||
isContainer: true, | ||
}; | ||
}, [upstreamInfo]); | ||
|
||
useEffect(() => { | ||
if (activeId === id && isExpanded) { | ||
setIsExpanded(false); | ||
|
@@ -149,6 +170,11 @@ const SectionCard = ({ | |
setIsExpanded((prevState) => containsSearchResult() || prevState); | ||
}, [locatorId, setIsExpanded]); | ||
|
||
const handleOnPostChangeSync = useCallback(() => { | ||
dispatch(fetchCourseSectionQuery([section.id])); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to invalidate course libraries query after syncing changes. Same for Subsection and unit cards. Vice versa, we need to refetch course section when the sync is performed from course libraries page. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Updated here: 6ebf564
I'm not sure this is necessary. Does the course libraries page display any course information? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No, just wanted to make sure that the outline is updated and the |
||
invalidateLinksQuery(queryClient, courseId); | ||
}, [dispatch, section]); | ||
|
||
// re-create actions object for customizations | ||
const actions = { ...sectionActions }; | ||
// add actions to control display of move up & down menu buton. | ||
|
@@ -267,6 +293,7 @@ const SectionCard = ({ | |
onClickDelete={onOpenDeleteModal} | ||
onClickMoveUp={handleSectionMoveUp} | ||
onClickMoveDown={handleSectionMoveDown} | ||
onClickSync={openSyncModal} | ||
isFormOpen={isFormOpen} | ||
closeForm={closeForm} | ||
onEditSubmit={handleEditSubmit} | ||
|
@@ -275,6 +302,7 @@ const SectionCard = ({ | |
titleComponent={titleComponent} | ||
namePrefix={namePrefix} | ||
actions={actions} | ||
readyToSync={upstreamInfo?.readyToSync} | ||
/> | ||
)} | ||
<div className="section-card__content" data-testid="section-card__content"> | ||
|
@@ -330,6 +358,14 @@ const SectionCard = ({ | |
visibleTabs={[ContentType.subsections]} | ||
/> | ||
</StandardModal> | ||
{blockSyncData && ( | ||
<PreviewLibraryXBlockChanges | ||
blockData={blockSyncData} | ||
isModalOpen={isSyncModalOpen} | ||
closeModal={closeSyncModal} | ||
postChange={handleOnPostChangeSync} | ||
/> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
Uh oh!
There was an error while loading. Please reload this page.