fix: don't use getAsset for draft entries (#3403)
This commit is contained in:
parent
e92ba412d8
commit
45a1654404
@ -349,7 +349,7 @@ describe('Backend', () => {
|
||||
init: jest.fn(() => implementation),
|
||||
unpublishedEntry: jest.fn().mockResolvedValue(unpublishedEntryResult),
|
||||
};
|
||||
const config = Map({});
|
||||
const config = Map({ media_folder: 'static/images' });
|
||||
|
||||
const backend = new Backend(implementation, { config, backendName: 'github' });
|
||||
|
||||
@ -357,9 +357,15 @@ describe('Backend', () => {
|
||||
name: 'posts',
|
||||
});
|
||||
|
||||
const state = {
|
||||
config,
|
||||
integrations: Map({}),
|
||||
mediaLibrary: Map({}),
|
||||
};
|
||||
|
||||
const slug = 'slug';
|
||||
|
||||
const result = await backend.unpublishedEntry(collection, slug);
|
||||
const result = await backend.unpublishedEntry(state, collection, slug);
|
||||
expect(result).toEqual({
|
||||
collection: 'posts',
|
||||
slug: '',
|
||||
@ -370,7 +376,7 @@ describe('Backend', () => {
|
||||
label: null,
|
||||
metaData: {},
|
||||
isModification: true,
|
||||
mediaFiles: [{ id: '1' }],
|
||||
mediaFiles: [{ id: '1', draft: true }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -38,7 +38,7 @@ describe('editorialWorkflow actions', () => {
|
||||
const { createAssetProxy } = require('ValueObjects/AssetProxy');
|
||||
|
||||
const assetProxy = { name: 'name', path: 'path' };
|
||||
const entry = { mediaFiles: [{ file: { name: 'name' }, id: '1' }] };
|
||||
const entry = { mediaFiles: [{ file: { name: 'name' }, id: '1', draft: true }] };
|
||||
const backend = {
|
||||
unpublishedEntry: jest.fn().mockResolvedValue(entry),
|
||||
};
|
||||
|
@ -8,15 +8,9 @@ import {
|
||||
} from '../entries';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
import AssetProxy from '../../valueObjects/AssetProxy';
|
||||
|
||||
jest.mock('coreSrc/backend');
|
||||
jest.mock('../media', () => {
|
||||
const media = jest.requireActual('../media');
|
||||
return {
|
||||
...media,
|
||||
getAsset: jest.fn(),
|
||||
};
|
||||
});
|
||||
jest.mock('netlify-cms-lib-util');
|
||||
jest.mock('../mediaLibrary');
|
||||
|
||||
@ -25,6 +19,13 @@ const mockStore = configureMockStore(middlewares);
|
||||
|
||||
describe('entries', () => {
|
||||
describe('createEmptyDraft', () => {
|
||||
const { currentBackend } = require('coreSrc/backend');
|
||||
const backend = {
|
||||
processEntry: jest.fn((_state, _collection, entry) => Promise.resolve(entry)),
|
||||
};
|
||||
|
||||
currentBackend.mockReturnValue(backend);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
@ -45,7 +46,7 @@ describe('entries', () => {
|
||||
data: {},
|
||||
isModification: null,
|
||||
label: null,
|
||||
mediaFiles: fromJS([]),
|
||||
mediaFiles: [],
|
||||
metaData: null,
|
||||
partial: false,
|
||||
path: '',
|
||||
@ -74,7 +75,7 @@ describe('entries', () => {
|
||||
data: { title: 'title', boolean: true },
|
||||
isModification: null,
|
||||
label: null,
|
||||
mediaFiles: fromJS([]),
|
||||
mediaFiles: [],
|
||||
metaData: null,
|
||||
partial: false,
|
||||
path: '',
|
||||
@ -105,7 +106,7 @@ describe('entries', () => {
|
||||
data: { title: '<script>alert('hello')</script>' },
|
||||
isModification: null,
|
||||
label: null,
|
||||
mediaFiles: fromJS([]),
|
||||
mediaFiles: [],
|
||||
metaData: null,
|
||||
partial: false,
|
||||
path: '',
|
||||
@ -286,20 +287,11 @@ describe('entries', () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should map mediaFiles to assets', async () => {
|
||||
const { getAsset } = require('../media');
|
||||
it('should map mediaFiles to assets', () => {
|
||||
const mediaFiles = fromJS([{ path: 'path1' }, { path: 'path2', draft: true }]);
|
||||
|
||||
const asset = { path: 'path1' };
|
||||
|
||||
getAsset.mockReturnValue(() => asset);
|
||||
|
||||
const collection = Map();
|
||||
const entry = Map({ mediaFiles });
|
||||
await expect(getMediaAssets({ entry, collection })).resolves.toEqual([asset]);
|
||||
|
||||
expect(getAsset).toHaveBeenCalledTimes(1);
|
||||
expect(getAsset).toHaveBeenCalledWith({ collection, path: 'path2', entry });
|
||||
expect(getMediaAssets({ entry })).toEqual([new AssetProxy({ path: 'path2' })]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -271,25 +271,20 @@ export function loadUnpublishedEntry(collection: Collection, slug: string) {
|
||||
dispatch(unpublishedEntryLoading(collection, slug));
|
||||
|
||||
try {
|
||||
const entry = (await backend.unpublishedEntry(collection, slug)) as EntryValue;
|
||||
const entry = (await backend.unpublishedEntry(state, collection, slug)) as EntryValue;
|
||||
const assetProxies = await Promise.all(
|
||||
entry.mediaFiles.map(({ url, file, path }) =>
|
||||
createAssetProxy({
|
||||
path,
|
||||
url,
|
||||
file,
|
||||
}),
|
||||
),
|
||||
entry.mediaFiles
|
||||
.filter(file => file.draft)
|
||||
.map(({ url, file, path }) =>
|
||||
createAssetProxy({
|
||||
path,
|
||||
url,
|
||||
file,
|
||||
}),
|
||||
),
|
||||
);
|
||||
dispatch(addAssets(assetProxies));
|
||||
|
||||
let mediaFiles: MediaFile[] = entry.mediaFiles.map(file => ({ ...file, draft: true }));
|
||||
if (!collection.has('media_folder')) {
|
||||
const libraryFiles = getState().mediaLibrary.get('files') || [];
|
||||
mediaFiles = mediaFiles.concat(libraryFiles);
|
||||
}
|
||||
|
||||
dispatch(unpublishedEntryLoaded(collection, { ...entry, mediaFiles }));
|
||||
dispatch(unpublishedEntryLoaded(collection, entry));
|
||||
dispatch(createDraftFromEntry(entry));
|
||||
} catch (error) {
|
||||
if (error.name === EDITORIAL_WORKFLOW_ERROR && error.notUnderEditorialWorkflow) {
|
||||
@ -375,10 +370,7 @@ export function persistUnpublishedEntry(collection: Collection, existingUnpublis
|
||||
const backend = currentBackend(state.config);
|
||||
const transactionID = uuid();
|
||||
const entry = entryDraft.get('entry');
|
||||
const assetProxies = await getMediaAssets({
|
||||
getState,
|
||||
dispatch,
|
||||
collection,
|
||||
const assetProxies = getMediaAssets({
|
||||
entry,
|
||||
});
|
||||
|
||||
|
@ -12,9 +12,9 @@ import { createEntry, EntryValue } from '../valueObjects/Entry';
|
||||
import AssetProxy, { createAssetProxy } from '../valueObjects/AssetProxy';
|
||||
import ValidationErrorTypes from '../constants/validationErrorTypes';
|
||||
import { addAssets, getAsset } from './media';
|
||||
import { Collection, EntryMap, MediaFile, State, EntryFields, EntryField } from '../types/redux';
|
||||
import { Collection, EntryMap, State, EntryFields, EntryField } from '../types/redux';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import { AnyAction, Dispatch } from 'redux';
|
||||
import { AnyAction } from 'redux';
|
||||
import { waitForMediaLibraryToLoad, loadMedia } from './mediaLibrary';
|
||||
import { waitUntil } from './waitUntil';
|
||||
|
||||
@ -524,13 +524,18 @@ export function createEmptyDraft(collection: Collection, search: string) {
|
||||
const fields = collection.get('fields', List());
|
||||
const dataFields = createEmptyDraftData(fields);
|
||||
|
||||
let mediaFiles = [] as MediaFile[];
|
||||
const state = getState();
|
||||
const backend = currentBackend(state.config);
|
||||
|
||||
if (!collection.has('media_folder')) {
|
||||
await waitForMediaLibraryToLoad(dispatch, getState());
|
||||
mediaFiles = getState().mediaLibrary.get('files');
|
||||
}
|
||||
|
||||
const newEntry = createEntry(collection.get('name'), '', '', { data: dataFields, mediaFiles });
|
||||
let newEntry = createEntry(collection.get('name'), '', '', {
|
||||
data: dataFields,
|
||||
mediaFiles: [],
|
||||
});
|
||||
newEntry = await backend.processEntry(state, collection, newEntry);
|
||||
dispatch(emptyDraftCreated(newEntry));
|
||||
};
|
||||
}
|
||||
@ -592,28 +597,13 @@ export function createEmptyDraftData(fields: EntryFields, withNameKey = true) {
|
||||
);
|
||||
}
|
||||
|
||||
export async function getMediaAssets({
|
||||
getState,
|
||||
dispatch,
|
||||
collection,
|
||||
entry,
|
||||
}: {
|
||||
getState: () => State;
|
||||
collection: Collection;
|
||||
entry: EntryMap;
|
||||
dispatch: Dispatch;
|
||||
}) {
|
||||
export function getMediaAssets({ entry }: { entry: EntryMap }) {
|
||||
const filesArray = entry.get('mediaFiles').toArray();
|
||||
const assets = await Promise.all(
|
||||
filesArray
|
||||
.filter(file => file.get('draft'))
|
||||
.map(file =>
|
||||
getAsset({ collection, entry, path: file.get('path'), field: file.get('field') })(
|
||||
dispatch,
|
||||
getState,
|
||||
),
|
||||
),
|
||||
);
|
||||
const assets = filesArray
|
||||
.filter(file => file.get('draft'))
|
||||
.map(file =>
|
||||
createAssetProxy({ path: file.get('path'), file: file.get('file'), url: file.get('url') }),
|
||||
);
|
||||
|
||||
return assets;
|
||||
}
|
||||
@ -648,10 +638,7 @@ export function persistEntry(collection: Collection) {
|
||||
|
||||
const backend = currentBackend(state.config);
|
||||
const entry = entryDraft.get('entry');
|
||||
const assetProxies = await getMediaAssets({
|
||||
getState,
|
||||
dispatch,
|
||||
collection,
|
||||
const assetProxies = getMediaAssets({
|
||||
entry,
|
||||
});
|
||||
|
||||
|
@ -198,6 +198,7 @@ function createMediaFileFromAsset({
|
||||
name: basename(assetProxy.path),
|
||||
displayURL: assetProxy.url,
|
||||
draft,
|
||||
file,
|
||||
size: file.size,
|
||||
url: assetProxy.url,
|
||||
path: assetProxy.path,
|
||||
|
@ -494,27 +494,16 @@ export class Backend {
|
||||
const path = selectEntryPath(collection, slug) as string;
|
||||
const label = selectFileEntryLabel(collection, slug);
|
||||
|
||||
const integration = selectIntegration(state.integrations, null, 'assetStore');
|
||||
|
||||
const loadedEntry = await this.implementation.getEntry(path);
|
||||
const entry = createEntry(collection.get('name'), slug, loadedEntry.file.path, {
|
||||
let entry = createEntry(collection.get('name'), slug, loadedEntry.file.path, {
|
||||
raw: loadedEntry.data,
|
||||
label,
|
||||
mediaFiles: [],
|
||||
});
|
||||
|
||||
const entryWithFormat = this.entryWithFormat(collection)(entry);
|
||||
const mediaFolders = selectMediaFolders(state, collection, fromJS(entryWithFormat));
|
||||
if (mediaFolders.length > 0 && !integration) {
|
||||
entry.mediaFiles = [];
|
||||
for (const folder of mediaFolders) {
|
||||
entry.mediaFiles = [...entry.mediaFiles, ...(await this.implementation.getMedia(folder))];
|
||||
}
|
||||
} else {
|
||||
entry.mediaFiles = state.mediaLibrary.get('files') || [];
|
||||
}
|
||||
|
||||
return entryWithFormat;
|
||||
entry = this.entryWithFormat(collection)(entry);
|
||||
entry = await this.processEntry(state, collection, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
getMedia() {
|
||||
@ -536,9 +525,9 @@ export class Backend {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
entryWithFormat(collectionOrEntity: unknown) {
|
||||
entryWithFormat(collection: Collection) {
|
||||
return (entry: EntryValue): EntryValue => {
|
||||
const format = resolveFormat(collectionOrEntity, entry);
|
||||
const format = resolveFormat(collection, entry);
|
||||
if (entry && entry.raw !== undefined) {
|
||||
const data = (format && attempt(format.fromFile.bind(format, entry.raw))) || {};
|
||||
if (isError(data)) console.error(data);
|
||||
@ -579,18 +568,37 @@ export class Backend {
|
||||
}));
|
||||
}
|
||||
|
||||
unpublishedEntry(collection: Collection, slug: string) {
|
||||
return this.implementation!.unpublishedEntry!(collection.get('name') as string, slug)
|
||||
.then(loadedEntry => {
|
||||
const entry = createEntry(collection.get('name'), loadedEntry.slug, loadedEntry.file.path, {
|
||||
raw: loadedEntry.data,
|
||||
isModification: loadedEntry.isModification,
|
||||
metaData: loadedEntry.metaData,
|
||||
mediaFiles: loadedEntry.mediaFiles,
|
||||
});
|
||||
return entry;
|
||||
})
|
||||
.then(this.entryWithFormat(collection));
|
||||
async processEntry(state: State, collection: Collection, entry: EntryValue) {
|
||||
const integration = selectIntegration(state.integrations, null, 'assetStore');
|
||||
const mediaFolders = selectMediaFolders(state, collection, fromJS(entry));
|
||||
if (mediaFolders.length > 0 && !integration) {
|
||||
const files = await Promise.all(
|
||||
mediaFolders.map(folder => this.implementation.getMedia(folder)),
|
||||
);
|
||||
entry.mediaFiles = entry.mediaFiles.concat(...files);
|
||||
} else {
|
||||
entry.mediaFiles = entry.mediaFiles.concat(state.mediaLibrary.get('files') || []);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
async unpublishedEntry(state: State, collection: Collection, slug: string) {
|
||||
const loadedEntry = await this.implementation!.unpublishedEntry!(
|
||||
collection.get('name') as string,
|
||||
slug,
|
||||
);
|
||||
|
||||
let entry = createEntry(collection.get('name'), loadedEntry.slug, loadedEntry.file.path, {
|
||||
raw: loadedEntry.data,
|
||||
isModification: loadedEntry.isModification,
|
||||
metaData: loadedEntry.metaData,
|
||||
mediaFiles: loadedEntry.mediaFiles?.map(file => ({ ...file, draft: true })) || [],
|
||||
});
|
||||
|
||||
entry = this.entryWithFormat(collection)(entry);
|
||||
entry = await this.processEntry(state, collection, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,15 +40,15 @@ const formatByName = (name, customDelimiter) =>
|
||||
'yaml-frontmatter': frontmatterYAML(customDelimiter),
|
||||
}[name]);
|
||||
|
||||
export function resolveFormat(collectionOrEntity, entry) {
|
||||
export function resolveFormat(collection, entry) {
|
||||
// Check for custom delimiter
|
||||
const frontmatter_delimiter = collectionOrEntity.get('frontmatter_delimiter');
|
||||
const frontmatter_delimiter = collection.get('frontmatter_delimiter');
|
||||
const customDelimiter = List.isList(frontmatter_delimiter)
|
||||
? frontmatter_delimiter.toArray()
|
||||
: frontmatter_delimiter;
|
||||
|
||||
// If the format is specified in the collection, use that format.
|
||||
const formatSpecification = collectionOrEntity.get('format');
|
||||
const formatSpecification = collection.get('format');
|
||||
if (formatSpecification) {
|
||||
return formatByName(formatSpecification, customDelimiter);
|
||||
}
|
||||
@ -62,7 +62,7 @@ export function resolveFormat(collectionOrEntity, entry) {
|
||||
|
||||
// If creating a new file, and an `extension` is specified in the
|
||||
// collection config, infer the format from that extension.
|
||||
const extension = collectionOrEntity.get('extension');
|
||||
const extension = collection.get('extension');
|
||||
if (extension) {
|
||||
return get(extensionFormatters, extension);
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ describe('entries', () => {
|
||||
folder: 'src/docs/getting-started',
|
||||
media_folder: '/static/images/docs/getting-started',
|
||||
}),
|
||||
fromJS({ path: 'src/docs/getting-started/with-github.md' }),
|
||||
fromJS({}),
|
||||
undefined,
|
||||
),
|
||||
).toEqual('static/images/docs/getting-started');
|
||||
@ -184,7 +184,6 @@ describe('entries', () => {
|
||||
};
|
||||
|
||||
const entry = fromJS({
|
||||
path: 'src/docs/extending/overview.md',
|
||||
data: { title: 'Overview' },
|
||||
});
|
||||
const collection = fromJS({
|
||||
|
@ -351,18 +351,15 @@ export const selectMediaFolder = (
|
||||
const customFolder = hasCustomFolder(name, collection, entryMap?.get('slug'), field);
|
||||
|
||||
if (customFolder) {
|
||||
const entryPath = entryMap?.get('path');
|
||||
if (entryPath) {
|
||||
const entryDir = dirname(entryPath);
|
||||
const folder = evaluateFolder(name, config, collection!, entryMap, field);
|
||||
const folder = evaluateFolder(name, config, collection!, entryMap, field);
|
||||
if (folder.startsWith('/')) {
|
||||
// return absolute paths as is
|
||||
if (folder.startsWith('/')) {
|
||||
mediaFolder = join(folder);
|
||||
} else {
|
||||
mediaFolder = join(entryDir, folder as string);
|
||||
}
|
||||
mediaFolder = join(folder);
|
||||
} else {
|
||||
mediaFolder = join(collection!.get('folder') as string, DRAFT_MEDIA_FILES);
|
||||
const entryPath = entryMap?.get('path');
|
||||
mediaFolder = entryPath
|
||||
? join(dirname(entryPath), folder)
|
||||
: join(collection!.get('folder') as string, DRAFT_MEDIA_FILES);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user