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' },
|
label_singular: { type: 'string' },
|
||||||
description: { type: 'string' },
|
description: { type: 'string' },
|
||||||
file: { type: 'string' },
|
file: { type: 'string' },
|
||||||
|
preview_path: { type: 'string' },
|
||||||
|
preview_path_date_field: { type: 'string' },
|
||||||
fields: fieldsConfig(),
|
fields: fieldsConfig(),
|
||||||
},
|
},
|
||||||
required: ['name', 'label', 'file', 'fields'],
|
required: ['name', 'label', 'file', 'fields'],
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Map, fromJS } from 'immutable';
|
import { List, Map, fromJS } from 'immutable';
|
||||||
import {
|
import {
|
||||||
commitMessageFormatter,
|
commitMessageFormatter,
|
||||||
prepareSlug,
|
prepareSlug,
|
||||||
@ -369,6 +369,68 @@ describe('formatters', () => {
|
|||||||
).toBe('https://www.example.com/2020/backendslug/title/entryslug');
|
).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', () => {
|
it('should infer date field when preview_path_date_field is not configured', () => {
|
||||||
const { selectInferedField } = require('../../reducers/collections');
|
const { selectInferedField } = require('../../reducers/collections');
|
||||||
selectInferedField.mockReturnValue('date');
|
selectInferedField.mockReturnValue('date');
|
||||||
|
@ -8,9 +8,11 @@ import {
|
|||||||
COMMIT_AUTHOR,
|
COMMIT_AUTHOR,
|
||||||
COMMIT_DATE,
|
COMMIT_DATE,
|
||||||
selectInferedField,
|
selectInferedField,
|
||||||
|
getFileFromSlug,
|
||||||
} from '../reducers/collections';
|
} from '../reducers/collections';
|
||||||
import { Collection, SlugConfig, Config, EntryMap } from '../types/redux';
|
import { Collection, SlugConfig, Config, EntryMap } from '../types/redux';
|
||||||
import { stripIndent } from 'common-tags';
|
import { stripIndent } from 'common-tags';
|
||||||
|
import { FILES } from '../constants/collectionTypes';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
compileStringTemplate,
|
compileStringTemplate,
|
||||||
@ -153,24 +155,35 @@ export const previewUrlFormatter = (
|
|||||||
return;
|
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.
|
* will be the URL provided by the backend.
|
||||||
*/
|
*/
|
||||||
if (!collection.get('preview_path')) {
|
if (!pathTemplate) {
|
||||||
return baseUrl;
|
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>;
|
let fields = entry.get('data') as Map<string, string>;
|
||||||
fields = addFileTemplateFields(entry.get('path'), fields, collection.get('folder'));
|
fields = addFileTemplateFields(entry.get('path'), fields, collection.get('folder'));
|
||||||
const dateFieldName =
|
const dateFieldName = getDateField() || selectInferedField(collection, 'date');
|
||||||
collection.get('preview_path_date_field') || selectInferedField(collection, 'date');
|
|
||||||
const date = parseDateFromEntry((entry as unknown) as Map<string, unknown>, dateFieldName);
|
const date = parseDateFromEntry((entry as unknown) as Map<string, unknown>, dateFieldName);
|
||||||
|
|
||||||
// Prepare and sanitize slug variables only, leave the rest of the
|
// Prepare and sanitize slug variables only, leave the rest of the
|
||||||
|
@ -140,6 +140,8 @@ export type CollectionFile = StaticallyTypedRecord<{
|
|||||||
label: string;
|
label: string;
|
||||||
media_folder?: string;
|
media_folder?: string;
|
||||||
public_folder?: string;
|
public_folder?: string;
|
||||||
|
preview_path?: string;
|
||||||
|
preview_path_date_field?: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type CollectionFiles = List<CollectionFile>;
|
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:
|
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
|
* Using editorial workflow
|
||||||
* Have a continuous deployment platform that builds every commit and provides statuses to your repo
|
* 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
|
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
|
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
|
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
|
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}}
|
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
|
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.
|
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
|
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
|
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
|
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