@@ -189,7 +195,7 @@ const LibraryCollectionPage = () => {
)}
void;
// Whether we're in "component picker" mode
componentPickerMode: boolean;
+ // Only show published components
+ showOnlyPublished: boolean;
// Sidebar stuff - only one sidebar is active at any given time:
closeLibrarySidebar: () => void;
openAddContentSidebar: () => void;
@@ -79,6 +81,7 @@ interface LibraryProviderProps {
/** The component picker mode is a special mode where the user is selecting a component to add to a Unit (or another
* XBlock) */
componentPickerMode?: boolean;
+ showOnlyPublished?: boolean;
/** Only used for testing */
initialSidebarComponentInfo?: SidebarComponentInfo;
}
@@ -91,6 +94,7 @@ export const LibraryProvider = ({
libraryId,
collectionId: collectionIdProp,
componentPickerMode = false,
+ showOnlyPublished = false,
initialSidebarComponentInfo,
}: LibraryProviderProps) => {
const [collectionId, setCollectionId] = useState(collectionIdProp);
@@ -148,6 +152,7 @@ export const LibraryProvider = ({
readOnly,
isLoadingLibraryData,
componentPickerMode,
+ showOnlyPublished,
closeLibrarySidebar,
openAddContentSidebar,
openInfoSidebar,
@@ -172,6 +177,7 @@ export const LibraryProvider = ({
readOnly,
isLoadingLibraryData,
componentPickerMode,
+ showOnlyPublished,
closeLibrarySidebar,
openAddContentSidebar,
openInfoSidebar,
diff --git a/src/library-authoring/component-info/ComponentInfoHeader.test.tsx b/src/library-authoring/component-info/ComponentInfoHeader.test.tsx
index fe55839859..832f0eebf0 100644
--- a/src/library-authoring/component-info/ComponentInfoHeader.test.tsx
+++ b/src/library-authoring/component-info/ComponentInfoHeader.test.tsx
@@ -8,7 +8,7 @@ import {
initializeMocks,
} from '../../testUtils';
import { mockContentLibrary } from '../data/api.mocks';
-import { getXBlockFieldsApiUrl } from '../data/api';
+import { getXBlockFieldsVersionApiUrl, getXBlockFieldsApiUrl } from '../data/api';
import { LibraryProvider, SidebarBodyComponentId } from '../common/context';
import ComponentInfoHeader from './ComponentInfoHeader';
@@ -45,7 +45,7 @@ describe('', () => {
beforeEach(() => {
const mocks = initializeMocks();
axiosMock = mocks.axiosMock;
- axiosMock.onGet(getXBlockFieldsApiUrl(usageKey)).reply(200, xBlockFields);
+ axiosMock.onGet(getXBlockFieldsVersionApiUrl(usageKey, 'draft')).reply(200, xBlockFields);
mockShowToast = mocks.mockShowToast;
});
@@ -97,7 +97,7 @@ describe('', () => {
});
it('should close edit library title on press Escape', async () => {
- const url = getXBlockFieldsApiUrl(usageKey);
+ const url = getXBlockFieldsVersionApiUrl(usageKey, 'draft');
axiosMock.onPost(url).reply(200);
render();
diff --git a/src/library-authoring/component-info/ComponentInfoHeader.tsx b/src/library-authoring/component-info/ComponentInfoHeader.tsx
index 5c27071255..295e4a3821 100644
--- a/src/library-authoring/component-info/ComponentInfoHeader.tsx
+++ b/src/library-authoring/component-info/ComponentInfoHeader.tsx
@@ -20,6 +20,7 @@ const ComponentInfoHeader = () => {
const {
sidebarComponentInfo,
readOnly,
+ showOnlyPublished,
} = useLibraryContext();
const usageKey = sidebarComponentInfo?.id;
@@ -29,7 +30,7 @@ const ComponentInfoHeader = () => {
}
const {
data: xblockFields,
- } = useXBlockFields(usageKey);
+ } = useXBlockFields(usageKey, showOnlyPublished ? 'published' : 'draft');
const updateMutation = useUpdateXBlockFields(usageKey);
const { showToast } = useContext(ToastContext);
diff --git a/src/library-authoring/component-info/ComponentPreview.tsx b/src/library-authoring/component-info/ComponentPreview.tsx
index a7448f3b8f..ba40e223e3 100644
--- a/src/library-authoring/component-info/ComponentPreview.tsx
+++ b/src/library-authoring/component-info/ComponentPreview.tsx
@@ -15,6 +15,7 @@ interface ModalComponentPreviewProps {
const ModalComponentPreview = ({ isOpen, close, usageKey }: ModalComponentPreviewProps) => {
const intl = useIntl();
+ const { showOnlyPublished } = useLibraryContext();
return (
-
+
);
};
@@ -33,7 +37,7 @@ const ComponentPreview = () => {
const intl = useIntl();
const [isModalOpen, openModal, closeModal] = useToggle();
- const { sidebarComponentInfo } = useLibraryContext();
+ const { sidebarComponentInfo, showOnlyPublished } = useLibraryContext();
const usageKey = sidebarComponentInfo?.id;
// istanbul ignore if: this should never happen
@@ -58,7 +62,13 @@ const ComponentPreview = () => {
{
// key=modified below is used to auto-refresh the preview when changes are made, e.g. via OLX editor
componentMetadata
- ?
+ ? (
+
+ )
: null
}
diff --git a/src/library-authoring/component-picker/ComponentPicker.test.tsx b/src/library-authoring/component-picker/ComponentPicker.test.tsx
index 29ecca195f..6341dfe1b6 100644
--- a/src/library-authoring/component-picker/ComponentPicker.test.tsx
+++ b/src/library-authoring/component-picker/ComponentPicker.test.tsx
@@ -17,6 +17,15 @@ import {
import { ComponentPicker } from './ComponentPicker';
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useLocation: () => ({
+ pathname: '/evilguy',
+ search: {
+ variant: 'published',
+ },
+ }),
+}));
mockContentLibrary.applyMock();
mockContentSearchConfig.applyMock();
mockGetCollectionMetadata.applyMock();
diff --git a/src/library-authoring/component-picker/ComponentPicker.tsx b/src/library-authoring/component-picker/ComponentPicker.tsx
index 372506d4cd..2502e1ac6b 100644
--- a/src/library-authoring/component-picker/ComponentPicker.tsx
+++ b/src/library-authoring/component-picker/ComponentPicker.tsx
@@ -1,4 +1,5 @@
import React, { useState } from 'react';
+import { useLocation } from 'react-router-dom';
import { Stepper } from '@openedx/paragon';
import { LibraryProvider, useLibraryContext } from '../common/context';
@@ -24,6 +25,11 @@ export const ComponentPicker = () => {
const [currentStep, setCurrentStep] = useState('select-library');
const [selectedLibrary, setSelectedLibrary] = useState('');
+ const location = useLocation();
+
+ const queryParams = new URLSearchParams(location.search);
+ const variant = queryParams.get('variant') || 'draft';
+
const handleLibrarySelection = (library: string) => {
setCurrentStep('pick-components');
setSelectedLibrary(library);
@@ -43,7 +49,7 @@ export const ComponentPicker = () => {
-
+
diff --git a/src/library-authoring/components/ComponentCard.test.tsx b/src/library-authoring/components/ComponentCard.test.tsx
index f5a8266453..fb5fb9685d 100644
--- a/src/library-authoring/components/ComponentCard.test.tsx
+++ b/src/library-authoring/components/ComponentCard.test.tsx
@@ -19,11 +19,13 @@ const contentHit: ContentHit = {
org: 'org1',
breadcrumbs: [{ displayName: 'Demo Lib' }],
displayName: 'Text Display Name',
+ description: 'This is a text: ID=1',
formatted: {
displayName: 'Text Display Formated Name',
content: {
htmlContent: 'This is a text: ID=1',
},
+ description: 'This is a text: ID=1',
},
tags: {
level0: ['1', '2', '3'],
diff --git a/src/library-authoring/components/ComponentCard.tsx b/src/library-authoring/components/ComponentCard.tsx
index 2d61b858cc..f0da3a51a0 100644
--- a/src/library-authoring/components/ComponentCard.tsx
+++ b/src/library-authoring/components/ComponentCard.tsx
@@ -106,6 +106,7 @@ const ComponentCard = ({ contentHit }: ComponentCardProps) => {
const {
openComponentInfoSidebar,
componentPickerMode,
+ showOnlyPublished,
} = useLibraryContext();
const {
@@ -114,12 +115,12 @@ const ComponentCard = ({ contentHit }: ComponentCardProps) => {
tags,
usageKey,
} = contentHit;
- const description: string = (/* eslint-disable */
- blockType === 'html' ? formatted?.content?.htmlContent :
- blockType === 'problem' ? formatted?.content?.capaContent :
- undefined
- ) ?? '';/* eslint-enable */
- const displayName = formatted?.displayName ?? '';
+ const componentDescription: string = (
+ showOnlyPublished ? formatted.published?.description : formatted.description
+ ) ?? '';
+ const displayName: string = (
+ showOnlyPublished ? formatted.published?.displayName : formatted.displayName
+ ) ?? '';
const handleAddComponentToCourse = () => {
window.parent.postMessage({
@@ -133,7 +134,7 @@ const ComponentCard = ({ contentHit }: ComponentCardProps) => {
diff --git a/src/library-authoring/data/api.ts b/src/library-authoring/data/api.ts
index 25b162e58b..c47f4bdc57 100644
--- a/src/library-authoring/data/api.ts
+++ b/src/library-authoring/data/api.ts
@@ -52,6 +52,8 @@ export const getLibraryPasteClipboardUrl = (libraryId: string) => `${getApiBaseU
* Get the URL for the xblock fields/metadata API.
*/
export const getXBlockFieldsApiUrl = (usageKey: string) => `${getApiBaseUrl()}/api/xblock/v2/xblocks/${usageKey}/fields/`;
+export const getXBlockFieldsVersionApiUrl = (usageKey: string, version: string) => `${getApiBaseUrl()}/api/xblock/v2/xblocks/${usageKey}@${version}/fields/`;
+
/**
* Get the URL for the xblock OLX API
*/
@@ -383,8 +385,8 @@ export async function getLibraryBlockMetadata(usageKey: string): Promise {
- const { data } = await getAuthenticatedHttpClient().get(getXBlockFieldsApiUrl(usageKey));
+export async function getXBlockFields(usageKey: string, version: string = 'draft'): Promise {
+ const { data } = await getAuthenticatedHttpClient().get(getXBlockFieldsVersionApiUrl(usageKey, version));
return camelCaseObject(data);
}
diff --git a/src/library-authoring/data/apiHooks.ts b/src/library-authoring/data/apiHooks.ts
index 88a6702f73..baba2bcfcd 100644
--- a/src/library-authoring/data/apiHooks.ts
+++ b/src/library-authoring/data/apiHooks.ts
@@ -89,7 +89,7 @@ export const xblockQueryKeys = {
*/
xblock: (usageKey?: string) => [...xblockQueryKeys.all, usageKey],
/** Fields (i.e. the content, display name, etc.) of an XBlock */
- xblockFields: (usageKey: string) => [...xblockQueryKeys.xblock(usageKey), 'fields'],
+ xblockFields: (usageKey: string, version: string = 'draft') => [...xblockQueryKeys.xblock(usageKey), 'fields', version],
/** OLX (XML representation of the fields/content) */
xblockOLX: (usageKey: string) => [...xblockQueryKeys.xblock(usageKey), 'OLX'],
/** assets (static files) */
@@ -290,10 +290,10 @@ export const useLibraryBlockMetadata = (usageId: string) => (
})
);
-export const useXBlockFields = (usageKey: string) => (
+export const useXBlockFields = (usageKey: string, version: string = 'draft') => (
useQuery({
- queryKey: xblockQueryKeys.xblockFields(usageKey),
- queryFn: () => getXBlockFields(usageKey),
+ queryKey: xblockQueryKeys.xblockFields(usageKey, version),
+ queryFn: () => getXBlockFields(usageKey, version),
enabled: !!usageKey,
})
);
diff --git a/src/search-manager/data/api.ts b/src/search-manager/data/api.ts
index b9ede51d5b..08bb0fd63b 100644
--- a/src/search-manager/data/api.ts
+++ b/src/search-manager/data/api.ts
@@ -127,9 +127,21 @@ export interface ContentHit extends BaseContentHit {
* - After that is the name and usage key of any parent Section/Subsection/Unit/etc.
*/
breadcrumbs: [{ displayName: string }, ...Array<{ displayName: string, usageKey: string }>];
+ description?: string;
content?: ContentDetails;
lastPublished: number | null;
- collections: { displayName?: string[], key?: string[] },
+ collections: { displayName?: string[], key?: string[] };
+ published?: ContentPublishedData;
+ formatted: BaseContentHit['formatted'] & { published?: ContentPublishedData, };
+}
+
+/**
+ * Information about the published data of single Xblock returned in search results
+ * Defined in edx-platform/openedx/core/djangoapps/content/search/documents.py
+ */
+export interface ContentPublishedData {
+ description?: string,
+ displayName?: string,
}
/**
@@ -152,6 +164,7 @@ export function formatSearchHit(hit: Record): ContentHit | Collecti
displayName: _formatted?.display_name,
content: _formatted?.content ?? {},
description: _formatted?.description,
+ published: _formatted?.published,
};
return camelCaseObject(newHit);
}
@@ -247,10 +260,10 @@ export async function fetchSearchResults({
...extraFilterFormatted,
...tagsFilterFormatted,
],
- attributesToHighlight: ['display_name', 'content'],
+ attributesToHighlight: ['display_name', 'description', 'published'],
highlightPreTag: HIGHLIGHT_PRE_TAG,
highlightPostTag: HIGHLIGHT_POST_TAG,
- attributesToCrop: ['content'],
+ attributesToCrop: ['description', 'published'],
sort,
offset,
limit,