feat: allow per-file preview_path in file collection (#4413)
This commit is contained in:
parent
a5750d782e
commit
9e0b8ac4b8
@ -187,6 +187,8 @@ const getConfigSchema = () => ({
|
||||
label_singular: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
file: { type: 'string' },
|
||||
preview_path: { type: 'string' },
|
||||
preview_path_date_field: { type: 'string' },
|
||||
fields: fieldsConfig(),
|
||||
},
|
||||
required: ['name', 'label', 'file', 'fields'],
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Map, fromJS } from 'immutable';
|
||||
import { List, Map, fromJS } from 'immutable';
|
||||
import {
|
||||
commitMessageFormatter,
|
||||
prepareSlug,
|
||||
@ -369,6 +369,68 @@ describe('formatters', () => {
|
||||
).toBe('https://www.example.com/2020/backendslug/title/entryslug');
|
||||
});
|
||||
|
||||
it('should return preview url for files in file collection', () => {
|
||||
const file = Map({ name: 'about-file', preview_path: '{{slug}}/{{fields.slug}}/{{title}}' });
|
||||
|
||||
const { getFileFromSlug } = require('../../reducers/collections');
|
||||
getFileFromSlug.mockReturnValue(file);
|
||||
|
||||
expect(
|
||||
previewUrlFormatter(
|
||||
'https://www.example.com',
|
||||
Map({
|
||||
preview_path: '{{slug}}/{{title}}/{{fields.slug}}',
|
||||
type: 'file_based_collection',
|
||||
files: List([file]),
|
||||
}),
|
||||
'backendSlug',
|
||||
slugConfig,
|
||||
Map({ data: Map({ slug: 'about-the-project', title: 'title' }), slug: 'about-file' }),
|
||||
),
|
||||
).toBe('https://www.example.com/backendslug/about-the-project/title');
|
||||
});
|
||||
|
||||
it('should return preview url for files in file collection when defined on file-level only', () => {
|
||||
const file = Map({ name: 'about-file', preview_path: '{{slug}}/{{fields.slug}}/{{title}}' });
|
||||
|
||||
const { getFileFromSlug } = require('../../reducers/collections');
|
||||
getFileFromSlug.mockReturnValue(file);
|
||||
|
||||
expect(
|
||||
previewUrlFormatter(
|
||||
'https://www.example.com',
|
||||
Map({
|
||||
type: 'file_based_collection',
|
||||
files: List([file]),
|
||||
}),
|
||||
'backendSlug',
|
||||
slugConfig,
|
||||
Map({ data: Map({ slug: 'about-the-project', title: 'title' }), slug: 'about-file' }),
|
||||
),
|
||||
).toBe('https://www.example.com/backendslug/about-the-project/title');
|
||||
});
|
||||
|
||||
it('should fall back to collection preview url for files in file collection', () => {
|
||||
const file = Map({ name: 'about-file' });
|
||||
|
||||
const { getFileFromSlug } = require('../../reducers/collections');
|
||||
getFileFromSlug.mockReturnValue(file);
|
||||
|
||||
expect(
|
||||
previewUrlFormatter(
|
||||
'https://www.example.com',
|
||||
Map({
|
||||
preview_path: '{{slug}}/{{title}}/{{fields.slug}}',
|
||||
type: 'file_based_collection',
|
||||
files: List([file]),
|
||||
}),
|
||||
'backendSlug',
|
||||
slugConfig,
|
||||
Map({ data: Map({ slug: 'about-the-project', title: 'title' }), slug: 'about-file' }),
|
||||
),
|
||||
).toBe('https://www.example.com/backendslug/title/about-the-project');
|
||||
});
|
||||
|
||||
it('should infer date field when preview_path_date_field is not configured', () => {
|
||||
const { selectInferedField } = require('../../reducers/collections');
|
||||
selectInferedField.mockReturnValue('date');
|
||||
|
@ -8,9 +8,11 @@ import {
|
||||
COMMIT_AUTHOR,
|
||||
COMMIT_DATE,
|
||||
selectInferedField,
|
||||
getFileFromSlug,
|
||||
} from '../reducers/collections';
|
||||
import { Collection, SlugConfig, Config, EntryMap } from '../types/redux';
|
||||
import { stripIndent } from 'common-tags';
|
||||
import { FILES } from '../constants/collectionTypes';
|
||||
|
||||
const {
|
||||
compileStringTemplate,
|
||||
@ -153,24 +155,35 @@ export const previewUrlFormatter = (
|
||||
return;
|
||||
}
|
||||
|
||||
const basePath = trimEnd(baseUrl, '/');
|
||||
|
||||
const isFileCollection = collection.get('type') === FILES;
|
||||
const file = isFileCollection ? getFileFromSlug(collection, entry.get('slug')) : undefined;
|
||||
|
||||
const getPathTemplate = () => {
|
||||
return file?.get('preview_path') ?? collection.get('preview_path');
|
||||
};
|
||||
const getDateField = () => {
|
||||
return file?.get('preview_path_date_field') ?? collection.get('preview_path_date_field');
|
||||
};
|
||||
|
||||
/**
|
||||
* Without a `previewPath` for the collection (via config), the preview URL
|
||||
* If a `previewPath` is provided for the collection/file, use it to construct the
|
||||
* URL path.
|
||||
*/
|
||||
const pathTemplate = getPathTemplate();
|
||||
|
||||
/**
|
||||
* Without a `previewPath` for the collection/file (via config), the preview URL
|
||||
* will be the URL provided by the backend.
|
||||
*/
|
||||
if (!collection.get('preview_path')) {
|
||||
if (!pathTemplate) {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a `previewPath` is provided for the collection, use it to construct the
|
||||
* URL path.
|
||||
*/
|
||||
const basePath = trimEnd(baseUrl, '/');
|
||||
const pathTemplate = collection.get('preview_path') as string;
|
||||
let fields = entry.get('data') as Map<string, string>;
|
||||
fields = addFileTemplateFields(entry.get('path'), fields, collection.get('folder'));
|
||||
const dateFieldName =
|
||||
collection.get('preview_path_date_field') || selectInferedField(collection, 'date');
|
||||
const dateFieldName = getDateField() || selectInferedField(collection, 'date');
|
||||
const date = parseDateFromEntry((entry as unknown) as Map<string, unknown>, dateFieldName);
|
||||
|
||||
// Prepare and sanitize slug variables only, leave the rest of the
|
||||
|
@ -140,6 +140,8 @@ export type CollectionFile = StaticallyTypedRecord<{
|
||||
label: string;
|
||||
media_folder?: string;
|
||||
public_folder?: string;
|
||||
preview_path?: string;
|
||||
preview_path_date_field?: string;
|
||||
}>;
|
||||
|
||||
export type CollectionFiles = List<CollectionFile>;
|
||||
|
@ -12,7 +12,7 @@ of your unmerged content.
|
||||
|
||||
Deploy preview links will work without configuration when all of the following requirements are met:
|
||||
|
||||
* Netlify CMS version is 2.4.0+ for GitHub support and 2.10.6+ for GitLab/Bitbucket support
|
||||
* Netlify CMS version is 2.4.0+ for GitHub support and 2.10.6+ for GitLab/Bitbucket support
|
||||
* Using editorial workflow
|
||||
* Have a continuous deployment platform that builds every commit and provides statuses to your repo
|
||||
|
||||
@ -40,7 +40,7 @@ pending, which a content editor can use to manually check for a finished preview
|
||||
|
||||
Deploy preview links point to the site root by default, but you'll probably want them to point to
|
||||
the specific piece of content that the content editor is viewing. You can do this by providing a
|
||||
`preview_path` string template for each collection.
|
||||
`preview_path` string template for each collection, or for inidividual files in a files collection.
|
||||
|
||||
Let's say we have a `blog` collection that stores content in our repo under `content/blog`. The path
|
||||
to a post in your repo may look like `content/blog/2018-01-new-post.md`, but the path to that post
|
||||
@ -55,6 +55,18 @@ collections:
|
||||
preview_path: blog/{{slug}}
|
||||
```
|
||||
|
||||
Similarly, for an `about` page in a files collection under `content/pages` which maps to `/about-the-project`
|
||||
on your site, you would configure `preview_path` like this:
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
- name: pages
|
||||
files:
|
||||
- name: about
|
||||
file: content/pages/about.md
|
||||
preview_path: about-the-project
|
||||
```
|
||||
|
||||
With the above configuration, the deploy preview URL from your backend will be combined with your
|
||||
preview path to create a URL to a specific blog post.
|
||||
|
||||
@ -134,4 +146,4 @@ a commit status back to your repository host with the URL.
|
||||
The deploy preview URL provided by a backend will lead to the root of the deployed site. Netlify CMS
|
||||
will then use the `preview_path` template in an entry's collection configuration to build a path to
|
||||
a specific piece of content. If a `preview_path` is not provided for an entry's collection, the URL
|
||||
will be used as is.
|
||||
will be used as is.
|
||||
|
Loading…
x
Reference in New Issue
Block a user