diff --git a/src/editors/EditorPage.test.tsx b/src/editors/EditorPage.test.tsx
index e4d0de409..4ae9817d3 100644
--- a/src/editors/EditorPage.test.tsx
+++ b/src/editors/EditorPage.test.tsx
@@ -11,7 +11,7 @@ import EditorPage from './EditorPage';
// Mock this plugins component:
jest.mock('frontend-components-tinymce-advanced-plugins', () => ({ a11ycheckerCss: '' }));
// Always mock out the "fetch course images" endpoint:
-jest.spyOn(editorCmsApi, 'fetchImages').mockImplementation(async () => ( // eslint-disable-next-line
+jest.spyOn(editorCmsApi, 'fetchCourseImages').mockImplementation(async () => ( // eslint-disable-next-line
{ data: { assets: [], start: 0, end: 0, page: 0, pageSize: 50, totalCount: 0 } }
));
// Mock out the 'get ancestors' API:
diff --git a/src/editors/containers/EditorContainer/index.test.tsx b/src/editors/containers/EditorContainer/index.test.tsx
index 3f427bbeb..a35e4d74b 100644
--- a/src/editors/containers/EditorContainer/index.test.tsx
+++ b/src/editors/containers/EditorContainer/index.test.tsx
@@ -13,7 +13,7 @@ import EditorPage from '../../EditorPage';
// Mock this plugins component:
jest.mock('frontend-components-tinymce-advanced-plugins', () => ({ a11ycheckerCss: '' }));
// Always mock out the "fetch course images" endpoint:
-jest.spyOn(editorCmsApi, 'fetchImages').mockImplementation(async () => ( // eslint-disable-next-line
+jest.spyOn(editorCmsApi, 'fetchCourseImages').mockImplementation(async () => ( // eslint-disable-next-line
{ data: { assets: [], start: 0, end: 0, page: 0, pageSize: 50, totalCount: 0 } }
));
// Mock out the 'get ancestors' API:
diff --git a/src/editors/data/redux/app/reducer.js b/src/editors/data/redux/app/reducer.js
index 043de8bf6..3e019c8a5 100644
--- a/src/editors/data/redux/app/reducer.js
+++ b/src/editors/data/redux/app/reducer.js
@@ -53,6 +53,7 @@ const app = createSlice({
images: { ...state.images, ...payload.images },
imageCount: payload.imageCount,
}),
+ resetImages: (state) => ({ ...state, images: {}, imageCount: 0 }),
setVideos: (state, { payload }) => ({ ...state, videos: payload }),
setCourseDetails: (state, { payload }) => ({ ...state, courseDetails: payload }),
setShowRawEditor: (state, { payload }) => ({
diff --git a/src/editors/data/redux/thunkActions/app.js b/src/editors/data/redux/thunkActions/app.js
index 478ef4240..09ab9eb61 100644
--- a/src/editors/data/redux/thunkActions/app.js
+++ b/src/editors/data/redux/thunkActions/app.js
@@ -103,12 +103,8 @@ export const initialize = (data) => (dispatch) => {
dispatch(module.fetchCourseDetails());
break;
case 'html':
- if (isLibraryKey(data.learningContextId)) {
- // eslint-disable-next-line no-console
- console.log('Not fetching image assets - not implemented yet for content libraries.');
- } else {
- dispatch(module.fetchImages({ pageNumber: 0 }));
- }
+ if (isLibraryKey(data.learningContextId)) { dispatch(actions.app.resetImages()); }
+ dispatch(module.fetchImages({ pageNumber: 0 }));
break;
default:
break;
diff --git a/src/editors/data/redux/thunkActions/requests.js b/src/editors/data/redux/thunkActions/requests.js
index 46f9d1a03..edff3bf87 100644
--- a/src/editors/data/redux/thunkActions/requests.js
+++ b/src/editors/data/redux/thunkActions/requests.js
@@ -1,4 +1,4 @@
-import { StrictDict } from '../../../utils';
+import { StrictDict, parseLibraryImageData, getLibraryImageAssets } from '../../../utils';
import { RequestKeys } from '../../constants/requests';
import api, { loadImages } from '../../services/cms/api';
@@ -10,6 +10,8 @@ import { selectors as appSelectors } from '../app';
// should be re-thought and cleaned up to avoid this pattern.
// eslint-disable-next-line import/no-self-import
import * as module from './requests';
+import { isLibraryKey } from '../../../../generic/key-utils';
+import { acceptedImgKeys } from '../../../sharedComponents/ImageUploadModal/SelectImageModal/utils';
// Similar to `import { actions, selectors } from '..';` but avoid circular imports:
const actions = { requests: requestsActions };
@@ -121,25 +123,55 @@ export const saveBlock = ({ content, ...rest }) => (dispatch, getState) => {
}));
};
export const uploadAsset = ({ asset, ...rest }) => (dispatch, getState) => {
+ const learningContextId = selectors.app.learningContextId(getState());
dispatch(module.networkRequest({
requestKey: RequestKeys.uploadAsset,
promise: api.uploadAsset({
- learningContextId: selectors.app.learningContextId(getState()),
+ learningContextId,
asset,
studioEndpointUrl: selectors.app.studioEndpointUrl(getState()),
+ blockId: selectors.app.blockId(getState()),
+ }).then((resp) => {
+ if (isLibraryKey(learningContextId)) {
+ return ({
+ ...resp,
+ data: { asset: parseLibraryImageData(resp.data) },
+ });
+ }
+ return resp;
}),
...rest,
}));
};
export const fetchImages = ({ pageNumber, ...rest }) => (dispatch, getState) => {
+ const learningContextId = selectors.app.learningContextId(getState());
+ if (isLibraryKey(learningContextId)) {
+ dispatch(module.networkRequest({
+ requestKey: RequestKeys.fetchImages,
+ promise: api
+ .fetchLibraryImages({
+ pageNumber,
+ blockId: selectors.app.blockId(getState()),
+ studioEndpointUrl: selectors.app.studioEndpointUrl(getState()),
+ learningContextId,
+ })
+ .then(({ data }) => {
+ const images = getLibraryImageAssets(data.files, Object.keys(acceptedImgKeys));
+ return { images, imageCount: Object.keys(images).length };
+ }),
+ ...rest,
+ }));
+ return;
+ }
dispatch(module.networkRequest({
requestKey: RequestKeys.fetchImages,
promise: api
- .fetchImages({
+ .fetchCourseImages({
pageNumber,
+ blockId: selectors.app.blockId(getState()),
studioEndpointUrl: selectors.app.studioEndpointUrl(getState()),
- learningContextId: selectors.app.learningContextId(getState()),
+ learningContextId,
})
.then(({ data }) => ({ images: loadImages(data.assets), imageCount: data.totalCount })),
...rest,
diff --git a/src/editors/data/redux/thunkActions/requests.test.js b/src/editors/data/redux/thunkActions/requests.test.js
index 4b5961b9e..ece541178 100644
--- a/src/editors/data/redux/thunkActions/requests.test.js
+++ b/src/editors/data/redux/thunkActions/requests.test.js
@@ -1,4 +1,4 @@
-import { keyStore } from '../../../utils';
+import { keyStore, parseLibraryImageData, getLibraryImageAssets } from '../../../utils';
import { RequestKeys } from '../../constants/requests';
import api from '../../services/cms/api';
import * as requests from './requests';
@@ -26,7 +26,8 @@ jest.mock('../../services/cms/api', () => ({
fetchByUnitId: ({ id, url }) => ({ id, url }),
fetchCourseDetails: (args) => args,
saveBlock: (args) => args,
- fetchImages: ({ id, url }) => ({ id, url }),
+ fetchCourseImages: ({ id, url }) => ({ id, url }),
+ fetchLibraryImages: ({ id, url }) => ({ id, url }),
fetchVideos: ({ id, url }) => ({ id, url }),
uploadAsset: (args) => args,
loadImages: jest.fn(),
@@ -40,6 +41,12 @@ jest.mock('../../services/cms/api', () => ({
uploadVideo: (args) => args,
}));
+jest.mock('../../../utils', () => ({
+ ...jest.requireActual('../../../utils'),
+ parseLibraryImageData: jest.fn(),
+ getLibraryImageAssets: jest.fn(() => ({})),
+}));
+
const apiKeys = keyStore(api);
let dispatch;
@@ -241,31 +248,59 @@ describe('requests thunkActions module', () => {
let fetchImages;
let loadImages;
let dispatchedAction;
- const expectedArgs = {
- studioEndpointUrl: selectors.app.studioEndpointUrl(testState),
- learningContextId: selectors.app.learningContextId(testState),
- };
- beforeEach(() => {
- fetchImages = jest.fn((args) => new Promise((resolve) => {
- resolve({ data: { assets: { fetchImages: args } } });
- }));
- jest.spyOn(api, apiKeys.fetchImages).mockImplementationOnce(fetchImages);
- loadImages = jest.spyOn(api, apiKeys.loadImages).mockImplementationOnce(() => ({}));
- requests.fetchImages({ ...fetchParams, onSuccess, onFailure })(dispatch, () => testState);
- [[dispatchedAction]] = dispatch.mock.calls;
+ describe('courses', () => {
+ beforeEach(() => {
+ fetchImages = jest.fn((args) => new Promise((resolve) => {
+ resolve({ data: { assets: { fetchImages: args } } });
+ }));
+ jest.spyOn(api, apiKeys.fetchCourseImages).mockImplementationOnce(fetchImages);
+ loadImages = jest.spyOn(api, apiKeys.loadImages).mockImplementationOnce(() => ({}));
+ requests.fetchImages({ ...fetchParams, onSuccess, onFailure })(dispatch, () => testState);
+ [[dispatchedAction]] = dispatch.mock.calls;
+ });
+ const expectedArgs = {
+ blockId: selectors.app.blockId(testState),
+ studioEndpointUrl: selectors.app.studioEndpointUrl(testState),
+ learningContextId: selectors.app.learningContextId(testState),
+ };
+ it('dispatches networkRequest', () => {
+ expect(dispatchedAction.networkRequest).not.toEqual(undefined);
+ });
+ test('forwards onSuccess and onFailure', () => {
+ expect(dispatchedAction.networkRequest.onSuccess).toEqual(onSuccess);
+ expect(dispatchedAction.networkRequest.onFailure).toEqual(onFailure);
+ });
+ test('api.fetchImages promise called with studioEndpointUrl and learningContextId', () => {
+ expect(fetchImages).toHaveBeenCalledWith(expectedArgs);
+ });
+ test('promise is chained with api.loadImages', () => {
+ expect(loadImages).toHaveBeenCalledWith({ fetchImages: expectedArgs });
+ });
+ test('promise is chained with api.loadImages', () => {
+ expect(loadImages).toHaveBeenCalledWith({ fetchImages: expectedArgs });
+ });
});
- it('dispatches networkRequest', () => {
- expect(dispatchedAction.networkRequest).not.toEqual(undefined);
- });
- test('forwards onSuccess and onFailure', () => {
- expect(dispatchedAction.networkRequest.onSuccess).toEqual(onSuccess);
- expect(dispatchedAction.networkRequest.onFailure).toEqual(onFailure);
- });
- test('api.fetchImages promise called with studioEndpointUrl and learningContextId', () => {
- expect(fetchImages).toHaveBeenCalledWith(expectedArgs);
- });
- test('promise is chained with api.loadImages', () => {
- expect(loadImages).toHaveBeenCalledWith({ fetchImages: expectedArgs });
+ describe('libraries', () => {
+ const expectedArgs = {
+ learningContextId: 'lib:demo',
+ studioEndpointUrl: selectors.app.studioEndpointUrl(testState),
+ blockId: selectors.app.blockId(testState),
+ };
+ beforeEach(() => {
+ jest.spyOn(selectors.app, 'learningContextId').mockImplementationOnce(() => ('lib:demo'));
+ fetchImages = jest.fn((args) => new Promise((resolve) => {
+ resolve({ data: { files: { fetchImages: args } } });
+ }));
+ jest.spyOn(api, apiKeys.fetchLibraryImages).mockImplementationOnce(fetchImages);
+ requests.fetchImages({
+ ...fetchParams, onSuccess, onFailure,
+ })(dispatch, () => testState);
+ [[dispatchedAction]] = dispatch.mock.calls;
+ });
+ test('api.fetchImages promise called with studioEndpointUrl and blockId', () => {
+ expect(fetchImages).toHaveBeenCalledWith(expectedArgs);
+ expect(getLibraryImageAssets).toHaveBeenCalled();
+ });
});
});
describe('fetchVideos', () => {
@@ -316,21 +351,62 @@ describe('requests thunkActions module', () => {
});
describe('uploadAsset', () => {
const asset = 'SoME iMage CoNtent As String';
- testNetworkRequestAction({
- action: requests.uploadAsset,
- args: { asset, ...fetchParams },
- expectedString: 'with uploadAsset promise',
- expectedData: {
- ...fetchParams,
- requestKey: RequestKeys.uploadAsset,
- promise: api.uploadAsset({
- learningContextId: selectors.app.learningContextId(testState),
- asset,
- studioEndpointUrl: selectors.app.studioEndpointUrl(testState),
- }),
- },
+ let uploadAsset;
+ let dispatchedAction;
+
+ describe('courses', () => {
+ const expectedArgs = {
+ learningContextId: selectors.app.learningContextId(testState),
+ studioEndpointUrl: selectors.app.studioEndpointUrl(testState),
+ blockId: selectors.app.blockId(testState),
+ asset,
+ };
+ beforeEach(() => {
+ uploadAsset = jest.fn((args) => new Promise((resolve) => {
+ resolve({ data: { asset: args } });
+ }));
+ jest.spyOn(api, apiKeys.uploadAsset).mockImplementationOnce(uploadAsset);
+ requests.uploadAsset({
+ asset, ...fetchParams, onSuccess, onFailure,
+ })(dispatch, () => testState);
+ [[dispatchedAction]] = dispatch.mock.calls;
+ });
+ it('dispatches networkRequest', () => {
+ expect(dispatchedAction.networkRequest).not.toEqual(undefined);
+ });
+ test('forwards onSuccess and onFailure', () => {
+ expect(dispatchedAction.networkRequest.onSuccess).toEqual(onSuccess);
+ expect(dispatchedAction.networkRequest.onFailure).toEqual(onFailure);
+ });
+ test('api.uploadAsset promise called with studioEndpointUrl, blockId and learningContextId', () => {
+ expect(uploadAsset).toHaveBeenCalledWith(expectedArgs);
+ });
+ });
+ describe('libraries', () => {
+ const expectedArgs = {
+ learningContextId: 'lib:demo',
+ studioEndpointUrl: selectors.app.studioEndpointUrl(testState),
+ blockId: selectors.app.blockId(testState),
+ asset,
+ };
+ beforeEach(() => {
+ jest.spyOn(selectors.app, 'learningContextId').mockImplementationOnce(() => ('lib:demo'));
+ uploadAsset = jest.fn((args) => new Promise((resolve) => {
+ resolve({ data: { asset: args } });
+ }));
+ jest.spyOn(api, apiKeys.uploadAsset).mockImplementationOnce(uploadAsset);
+ requests.uploadAsset({
+ asset, ...fetchParams, onSuccess, onFailure,
+ })(dispatch, () => testState);
+ [[dispatchedAction]] = dispatch.mock.calls;
+ });
+ test('api.uploadAsset promise called with studioEndpointUrl and blockId', () => {
+ expect(uploadAsset).toHaveBeenCalledWith(expectedArgs);
+ expect(parseLibraryImageData).toHaveBeenCalled();
+ });
});
});
+
describe('uploadThumbnail', () => {
const thumbnail = 'SoME tHumbNAil CoNtent As String';
const videoId = 'SoME VidEOid CoNtent As String';
diff --git a/src/editors/data/services/cms/api.test.ts b/src/editors/data/services/cms/api.test.ts
index d7b553fb9..c3df32ccb 100644
--- a/src/editors/data/services/cms/api.test.ts
+++ b/src/editors/data/services/cms/api.test.ts
@@ -1,12 +1,15 @@
import * as api from './api';
import * as urls from './urls';
-import { get, post, deleteObject } from './utils';
+import {
+ get, post, put, deleteObject,
+} from './utils';
jest.mock('./urls', () => ({
block: jest.fn().mockReturnValue('urls.block'),
blockAncestor: jest.fn().mockReturnValue('urls.blockAncestor'),
blockStudioView: jest.fn().mockReturnValue('urls.StudioView'),
courseAssets: jest.fn().mockReturnValue('urls.courseAssets'),
+ libraryAssets: jest.fn().mockReturnValue('urls.libraryAssets'),
videoTranscripts: jest.fn().mockReturnValue('urls.videoTranscripts'),
allowThumbnailUpload: jest.fn().mockReturnValue('urls.allowThumbnailUpload'),
thumbnailUpload: jest.fn().mockReturnValue('urls.thumbnailUpload'),
@@ -25,19 +28,21 @@ jest.mock('./urls', () => ({
jest.mock('./utils', () => ({
get: jest.fn().mockName('get'),
post: jest.fn().mockName('post'),
+ put: jest.fn().mockName('put'),
deleteObject: jest.fn().mockName('deleteObject'),
}));
const { apiMethods } = api;
const blockId = 'block-v1-coursev1:2uX@4345432';
-const learningContextId = 'demo2uX';
+let learningContextId;
const studioEndpointUrl = 'hortus.coa';
const title = 'remember this needs to go into metadata to save';
describe('cms api', () => {
beforeEach(() => {
jest.clearAllMocks();
+ learningContextId = 'demo2uX';
});
describe('apiMethods', () => {
describe('fetchBlockId', () => {
@@ -100,9 +105,11 @@ describe('cms api', () => {
});
});
- describe('fetchImages', () => {
+ describe('fetchCourseImages', () => {
it('should call get with url.courseAssets', () => {
- apiMethods.fetchImages({ learningContextId, studioEndpointUrl, pageNumber: 0 });
+ apiMethods.fetchCourseImages({
+ learningContextId, studioEndpointUrl, pageNumber: 0,
+ });
const params = {
asset_type: 'Images',
page: 0,
@@ -113,6 +120,16 @@ describe('cms api', () => {
);
});
});
+ describe('fetchLibraryImages', () => {
+ it('should call get with urls.libraryAssets for library V2', () => {
+ apiMethods.fetchLibraryImages({
+ blockId,
+ });
+ expect(get).toHaveBeenCalledWith(
+ urls.libraryAssets({ blockId }),
+ );
+ });
+ });
describe('fetchCourseDetails', () => {
it('should call get with url.courseDetailsUrl', () => {
@@ -246,11 +263,14 @@ describe('cms api', () => {
});
describe('uploadAsset', () => {
- const asset = new Blob(['data'], { type: 'image/jpeg' });
+ const img = new Blob(['data'], { type: 'image/jpeg' });
+ const filename = 'image.jpg';
+ const asset = new File([img], filename, { type: 'image/jpeg' });
+ const mockFormdata = new FormData();
+ mockFormdata.append('file', asset);
it('should call post with urls.courseAssets and imgdata', () => {
- const mockFormdata = new FormData();
- mockFormdata.append('file', asset);
apiMethods.uploadAsset({
+ blockId,
learningContextId,
studioEndpointUrl,
asset,
@@ -260,6 +280,20 @@ describe('cms api', () => {
mockFormdata,
);
});
+ it('should call post with urls.libraryAssets and imgdata', () => {
+ learningContextId = 'lib:demo2uX';
+ mockFormdata.append('content', asset);
+ apiMethods.uploadAsset({
+ blockId,
+ learningContextId,
+ studioEndpointUrl,
+ asset,
+ });
+ expect(put).toHaveBeenCalledWith(
+ `${urls.libraryAssets({ blockId, assetName: asset.name })}`,
+ mockFormdata,
+ );
+ });
});
describe('uploadVideo', () => {
diff --git a/src/editors/data/services/cms/api.ts b/src/editors/data/services/cms/api.ts
index d40c9d5f3..e979eb445 100644
--- a/src/editors/data/services/cms/api.ts
+++ b/src/editors/data/services/cms/api.ts
@@ -2,7 +2,9 @@ import type { AxiosRequestConfig } from 'axios';
import { camelizeKeys } from '../../../utils';
import { isLibraryKey } from '../../../../generic/key-utils';
import * as urls from './urls';
-import { get, post, deleteObject } from './utils';
+import {
+ get, post, put, deleteObject,
+} from './utils';
import { durationStringFromValue } from '../../../containers/VideoEditor/components/VideoSettingsModal/components/DurationWidget/hooks';
const fetchByUnitIdOptions: AxiosRequestConfig = {};
@@ -115,19 +117,11 @@ export const apiMethods = {
fetchStudioView: ({ blockId, studioEndpointUrl }) => get(
urls.blockStudioView({ studioEndpointUrl, blockId }),
),
- fetchImages: ({
+ fetchCourseImages: ({
learningContextId,
studioEndpointUrl,
pageNumber,
}): Promise<{ data: AssetResponse & Pagination }> => {
- if (isLibraryKey(learningContextId)) {
- // V2 content libraries don't support static assets yet:
- return Promise.resolve({
- data: {
- assets: [], start: 0, end: 0, page: 0, pageSize: 50, totalCount: 0,
- },
- });
- }
const params = {
asset_type: 'Images',
page: pageNumber,
@@ -137,6 +131,9 @@ export const apiMethods = {
{ params },
);
},
+ fetchLibraryImages: ({ blockId }) => get(
+ `${urls.libraryAssets({ blockId })}`,
+ ),
fetchVideos: ({ studioEndpointUrl, learningContextId }) => get(
urls.courseVideos({ studioEndpointUrl, learningContextId }),
),
@@ -147,12 +144,20 @@ export const apiMethods = {
urls.courseAdvanceSettings({ studioEndpointUrl, learningContextId }),
),
uploadAsset: ({
+ blockId,
learningContextId,
studioEndpointUrl,
asset,
}) => {
const data = new FormData();
data.append('file', asset);
+ if (isLibraryKey(learningContextId)) {
+ data.set('content', asset);
+ return put(
+ `${urls.libraryAssets({ blockId, assetName: asset.name })}`,
+ data,
+ );
+ }
return post(
urls.courseAssets({ studioEndpointUrl, learningContextId }),
data,
diff --git a/src/editors/data/services/cms/urls.ts b/src/editors/data/services/cms/urls.ts
index 361849991..a137ffb9f 100644
--- a/src/editors/data/services/cms/urls.ts
+++ b/src/editors/data/services/cms/urls.ts
@@ -1,4 +1,5 @@
import { isLibraryKey, isLibraryV1Key } from '../../../../generic/key-utils';
+import { getXBlockAssetsApiUrl } from '../../../../library-authoring/data/api';
/**
* A little helper so we can write the types of these functions more compactly
@@ -61,6 +62,12 @@ export const courseAssets = (({ studioEndpointUrl, learningContextId }) => (
`${studioEndpointUrl}/assets/${learningContextId}/`
)) satisfies UrlFunction;
+export const libraryAssets = (({ blockId, assetName }) => (
+ assetName
+ ? `${getXBlockAssetsApiUrl(blockId)}static/${encodeURI(assetName)}`
+ : `${getXBlockAssetsApiUrl(blockId)}`
+)) satisfies UrlFunction;
+
export const thumbnailUpload = (({ studioEndpointUrl, learningContextId, videoId }) => (
`${studioEndpointUrl}/video_images/${learningContextId}/${videoId}`
)) satisfies UrlFunction;
diff --git a/src/editors/data/services/cms/utils.ts b/src/editors/data/services/cms/utils.ts
index b7d6276fe..2e77435cd 100644
--- a/src/editors/data/services/cms/utils.ts
+++ b/src/editors/data/services/cms/utils.ts
@@ -16,6 +16,13 @@ export const get: Axios['get'] = (...args) => client().get(...args);
* @param {object|string} data - post payload
*/
export const post: Axios['post'] = (...args) => client().post(...args);
+
+/**
+ * put(url, data)
+ * simple wrapper providing an authenticated Http client put action
+ */
+export const put: Axios['put'] = (...args) => client().put(...args);
+
/**
* delete(url, data)
* simple wrapper providing an authenticated Http client delete action
diff --git a/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/__snapshots__/index.test.jsx.snap b/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/__snapshots__/index.test.jsx.snap
index fd2b660d1..f94b18b18 100644
--- a/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/__snapshots__/index.test.jsx.snap
+++ b/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/__snapshots__/index.test.jsx.snap
@@ -9,8 +9,10 @@ exports[`SelectImageModal component snapshot 1`] = `
"jpeg": ".jpeg",
"jpg": ".jpg",
"png": ".png",
+ "svg": ".svg",
"tif": ".tif",
"tiff": ".tiff",
+ "webp": ".webp",
}
}
close={[MockFunction props.close]}
@@ -59,7 +61,7 @@ exports[`SelectImageModal component snapshot 1`] = `
"id": "authoring.texteditor.selectimagemodal.next.label",
},
"fetchError": {
- "defaultMessage": "Failed to obtain course images. Please try again.",
+ "defaultMessage": "Failed to obtain images. Please try again.",
"description": "Message presented to user when images are not found",
"id": "authoring.texteditor.selectimagemodal.error.fetchImagesError",
},
diff --git a/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/index.jsx b/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/index.jsx
index 81e4802cb..0e0439a58 100644
--- a/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/index.jsx
+++ b/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/index.jsx
@@ -17,6 +17,7 @@ const SelectImageModal = ({
isLoaded,
isFetchError,
isUploadError,
+ isLibrary,
imageCount,
}) => {
const {
@@ -57,6 +58,7 @@ const SelectImageModal = ({
isLoaded,
isFetchError,
isUploadError,
+ isLibrary,
}}
/>
);
@@ -73,12 +75,14 @@ SelectImageModal.propTypes = {
isFetchError: PropTypes.bool.isRequired,
isUploadError: PropTypes.bool.isRequired,
imageCount: PropTypes.number.isRequired,
+ isLibrary: PropTypes.bool,
};
export const mapStateToProps = (state) => ({
isLoaded: selectors.requests.isFinished(state, { requestKey: RequestKeys.fetchImages }),
isFetchError: selectors.requests.isFailed(state, { requestKey: RequestKeys.fetchImages }),
isUploadError: selectors.requests.isFailed(state, { requestKey: RequestKeys.uploadAsset }),
+ isLibrary: selectors.app.isLibrary(state),
imageCount: state.app.imageCount,
});
diff --git a/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/messages.js b/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/messages.js
index f39c30779..14794b641 100644
--- a/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/messages.js
+++ b/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/messages.js
@@ -56,7 +56,7 @@ const messages = defineMessages({
},
fetchImagesError: {
id: 'authoring.texteditor.selectimagemodal.error.fetchImagesError',
- defaultMessage: 'Failed to obtain course images. Please try again.',
+ defaultMessage: 'Failed to obtain images. Please try again.',
description: 'Message presented to user when images are not found',
},
fileSizeError: {
diff --git a/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/utils.js b/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/utils.js
index a94a6ebf2..a1af9fa61 100644
--- a/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/utils.js
+++ b/src/editors/sharedComponents/ImageUploadModal/SelectImageModal/utils.js
@@ -44,4 +44,6 @@ export const acceptedImgKeys = StrictDict({
tif: '.tif',
tiff: '.tiff',
ico: '.ico',
+ svg: '.svg',
+ webp: '.webp',
});
diff --git a/src/editors/sharedComponents/ImageUploadModal/index.jsx b/src/editors/sharedComponents/ImageUploadModal/index.jsx
index e5a705ce3..fea13225c 100644
--- a/src/editors/sharedComponents/ImageUploadModal/index.jsx
+++ b/src/editors/sharedComponents/ImageUploadModal/index.jsx
@@ -21,12 +21,17 @@ export const imgProps = ({
selection,
lmsEndpointUrl,
editorType,
+ isLibrary,
}) => {
let url = selection?.externalUrl;
if (url?.startsWith(lmsEndpointUrl) && editorType !== 'expandable') {
const sourceEndIndex = lmsEndpointUrl.length;
url = url.substring(sourceEndIndex);
}
+ if (isLibrary) {
+ const index = url.indexOf('static/');
+ url = url.substring(index);
+ }
return {
src: url,
alt: settings.isDecorative ? '' : settings.altText,
@@ -36,13 +41,14 @@ export const imgProps = ({
};
export const saveToEditor = ({
- settings, selection, lmsEndpointUrl, editorType, editorRef,
+ settings, selection, lmsEndpointUrl, editorType, editorRef, isLibrary,
}) => {
const newImgTag = module.hooks.imgTag({
settings,
selection,
lmsEndpointUrl,
editorType,
+ isLibrary,
});
editorRef.current.execCommand(
@@ -103,12 +109,14 @@ export const hooks = {
selection,
lmsEndpointUrl,
editorType,
+ isLibrary,
}) => {
const props = module.imgProps({
settings,
selection,
lmsEndpointUrl,
editorType,
+ isLibrary,
});
return ``;
},
@@ -130,6 +138,7 @@ const ImageUploadModal = ({
images,
editorType,
lmsEndpointUrl,
+ isLibrary,
}) => {
if (selection && selection.externalUrl) {
return (
@@ -148,6 +157,7 @@ const ImageUploadModal = ({
setSelection,
lmsEndpointUrl,
clearSelection,
+ isLibrary,
}),
returnToSelection: clearSelection,
}}
@@ -190,6 +200,7 @@ ImageUploadModal.propTypes = {
images: PropTypes.shape({}).isRequired,
lmsEndpointUrl: PropTypes.string.isRequired,
editorType: PropTypes.string,
+ isLibrary: PropTypes.string,
};
export const ImageUploadModalInternal = ImageUploadModal; // For testing only
diff --git a/src/editors/sharedComponents/SelectionModal/Gallery.jsx b/src/editors/sharedComponents/SelectionModal/Gallery.jsx
index 1e01a109f..fc71e81cb 100644
--- a/src/editors/sharedComponents/SelectionModal/Gallery.jsx
+++ b/src/editors/sharedComponents/SelectionModal/Gallery.jsx
@@ -23,6 +23,7 @@ const Gallery = ({
showIdsOnCards,
height,
isLoaded,
+ isLibrary,
thumbnailFallback,
allowLazyLoad,
fetchNextPage,
@@ -79,7 +80,7 @@ const Gallery = ({
/>
)) }
- {allowLazyLoad && (
+ {(allowLazyLoad && !isLibrary) && (