feat: expanded folder collection filter support (#820)
This commit is contained in:
parent
85db6b4f8d
commit
061febfd02
@ -39,6 +39,7 @@ import {
|
||||
selectInferredField,
|
||||
selectMediaFolders,
|
||||
} from './lib/util/collection.util';
|
||||
import filterEntries from './lib/util/filter.util';
|
||||
import {
|
||||
DRAFT_MEDIA_FILES,
|
||||
selectMediaFilePath,
|
||||
@ -1020,15 +1021,8 @@ export class Backend<EF extends BaseField = UnknownField, BC extends BackendClas
|
||||
return file.fields.map(f => f.name);
|
||||
}
|
||||
|
||||
filterEntries(collection: { entries: Entry[] }, filterRule: FilterRule) {
|
||||
return collection.entries.filter(entry => {
|
||||
const fieldValue = entry.data?.[filterRule.field];
|
||||
// TODO Investigate when the value could be a string array
|
||||
// if (Array.isArray(fieldValue)) {
|
||||
// return fieldValue.includes(filterRule.value);
|
||||
// }
|
||||
return fieldValue === filterRule.value;
|
||||
});
|
||||
filterEntries(collection: { entries: Entry[] }, filterRule: FilterRule | FilterRule[]) {
|
||||
return filterEntries(collection.entries, filterRule);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,11 +170,27 @@ export interface EntryDraft {
|
||||
fieldsErrors: FieldsErrors;
|
||||
}
|
||||
|
||||
export interface FilterRule {
|
||||
value: string;
|
||||
export interface BaseFieldFilterRule {
|
||||
field: string;
|
||||
}
|
||||
|
||||
export interface FieldPatternFilterRule extends BaseFieldFilterRule {
|
||||
pattern: string;
|
||||
}
|
||||
|
||||
export interface FieldValueFilterRule extends BaseFieldFilterRule {
|
||||
value: string | string[];
|
||||
matchAll?: boolean;
|
||||
}
|
||||
|
||||
export type FieldFilterRule = FieldPatternFilterRule | FieldValueFilterRule;
|
||||
|
||||
export interface FileNameFilterRule {
|
||||
pattern: string;
|
||||
}
|
||||
|
||||
export type FilterRule = FieldFilterRule | FileNameFilterRule;
|
||||
|
||||
export interface EditorConfig {
|
||||
preview?: boolean;
|
||||
frame?: boolean;
|
||||
@ -224,7 +240,7 @@ export interface BaseCollection {
|
||||
isFetching?: boolean;
|
||||
summary?: string;
|
||||
summary_fields?: string[];
|
||||
filter?: FilterRule;
|
||||
filter?: FilterRule | FilterRule[];
|
||||
label_singular?: string;
|
||||
label: string;
|
||||
sortable_fields?: SortableFields;
|
||||
|
200
packages/core/src/lib/util/__tests__/filter.util.spec.ts
Normal file
200
packages/core/src/lib/util/__tests__/filter.util.spec.ts
Normal file
@ -0,0 +1,200 @@
|
||||
import { createMockEntry } from '@staticcms/test/data/entry.mock';
|
||||
import filterEntries from '../filter.util';
|
||||
|
||||
import type { Entry } from '@staticcms/core/interface';
|
||||
|
||||
describe('filterEntries', () => {
|
||||
const mockEnglishEntry = createMockEntry({
|
||||
path: 'path/to/file-1.md',
|
||||
data: {
|
||||
language: 'en',
|
||||
tags: ['tag-1', 'tag-2', 'fish-catfish'],
|
||||
},
|
||||
});
|
||||
|
||||
const mockFrenchEntry = createMockEntry({
|
||||
path: 'path/to/file-2.md',
|
||||
data: {
|
||||
language: 'fr',
|
||||
tags: ['tag-1', 'tag-4'],
|
||||
},
|
||||
});
|
||||
|
||||
const mockIndexEntry = createMockEntry({
|
||||
path: 'path/to/index.md',
|
||||
data: {
|
||||
language: 'gr',
|
||||
tags: ['tag-1', 'tag-4'],
|
||||
},
|
||||
});
|
||||
|
||||
const mockUnderscoreIndexEntry = createMockEntry({
|
||||
path: 'path/to/_index.md',
|
||||
data: {
|
||||
language: 'gr',
|
||||
tags: ['tag-1', 'tag-3'],
|
||||
},
|
||||
});
|
||||
|
||||
const mockRandomFileNameEntry = createMockEntry({
|
||||
path: 'path/to/someOtherFile.md',
|
||||
data: {
|
||||
language: 'gr',
|
||||
tags: ['tag-3'],
|
||||
},
|
||||
});
|
||||
|
||||
const mockTags1and4Entry = createMockEntry({
|
||||
path: 'path/to/thatOtherPost.md',
|
||||
data: {
|
||||
language: 'gr',
|
||||
tags: ['tag-1', 'tag-4', 'fish-pike'],
|
||||
},
|
||||
});
|
||||
|
||||
const entries: Entry[] = [
|
||||
mockEnglishEntry,
|
||||
mockFrenchEntry,
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
mockRandomFileNameEntry,
|
||||
mockTags1and4Entry,
|
||||
];
|
||||
|
||||
describe('field rules', () => {
|
||||
it('should filter fields', () => {
|
||||
expect(filterEntries(entries, { field: 'language', value: 'en' })).toEqual([
|
||||
mockEnglishEntry,
|
||||
]);
|
||||
|
||||
expect(filterEntries(entries, { field: 'language', value: 'fr' })).toEqual([mockFrenchEntry]);
|
||||
|
||||
expect(filterEntries(entries, { field: 'language', value: 'gr' })).toEqual([
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
mockRandomFileNameEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter fields if multiple filter values are provided (must match only one)', () => {
|
||||
expect(filterEntries(entries, { field: 'language', value: ['en', 'fr'] })).toEqual([
|
||||
mockEnglishEntry,
|
||||
mockFrenchEntry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter fields based on pattern', () => {
|
||||
// Languages with an r in their name
|
||||
expect(filterEntries(entries, { field: 'language', pattern: 'r' })).toEqual([
|
||||
mockFrenchEntry,
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
mockRandomFileNameEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter fields if field value is an array (must include value)', () => {
|
||||
expect(filterEntries(entries, { field: 'tags', value: 'tag-4' })).toEqual([
|
||||
mockFrenchEntry,
|
||||
mockIndexEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter fields if field value is an array and multiple filter values are provided (must include only one)', () => {
|
||||
expect(filterEntries(entries, { field: 'tags', value: ['tag-3', 'tag-4'] })).toEqual([
|
||||
mockFrenchEntry,
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
mockRandomFileNameEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter fields if field value is an array and multiple filter values are provided (must include only one)', () => {
|
||||
expect(filterEntries(entries, { field: 'tags', value: ['tag-3', 'tag-4'] })).toEqual([
|
||||
mockFrenchEntry,
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
mockRandomFileNameEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should match all values if matchAll is one (value is an array, multiple filter values are provided)', () => {
|
||||
expect(
|
||||
filterEntries(entries, { field: 'tags', value: ['tag-1', 'tag-4'], matchAll: true }),
|
||||
).toEqual([mockFrenchEntry, mockIndexEntry, mockTags1and4Entry]);
|
||||
});
|
||||
|
||||
it('should filter fields based on pattern when value is an array', () => {
|
||||
// Tags containing the word "fish"
|
||||
expect(filterEntries(entries, { field: 'tags', pattern: 'fish' })).toEqual([
|
||||
mockEnglishEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter based on multiple rules (must match all rules)', () => {
|
||||
expect(
|
||||
filterEntries(entries, [
|
||||
{ field: 'tags', value: ['tag-3', 'tag-4'] },
|
||||
{ field: 'language', value: 'gr' },
|
||||
]),
|
||||
).toEqual([
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
mockRandomFileNameEntry,
|
||||
mockTags1and4Entry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter based on multiple rules (must match all rules) (matchAll on)', () => {
|
||||
expect(
|
||||
filterEntries(entries, [
|
||||
{ field: 'tags', value: ['tag-1', 'tag-4'], matchAll: true },
|
||||
{ field: 'language', value: 'gr' },
|
||||
]),
|
||||
).toEqual([mockIndexEntry, mockTags1and4Entry]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('file rule', () => {
|
||||
it('should filter based on file name', () => {
|
||||
expect(filterEntries(entries, { pattern: '^index.md$' })).toEqual([mockIndexEntry]);
|
||||
|
||||
expect(filterEntries(entries, { pattern: '^_index.md$' })).toEqual([
|
||||
mockUnderscoreIndexEntry,
|
||||
]);
|
||||
|
||||
expect(filterEntries(entries, { pattern: 'index.md$' })).toEqual([
|
||||
mockIndexEntry,
|
||||
mockUnderscoreIndexEntry,
|
||||
]);
|
||||
|
||||
// File names containing the word file (case insensitive)
|
||||
expect(filterEntries(entries, { pattern: '[fF][iI][lL][eE]' })).toEqual([
|
||||
mockEnglishEntry,
|
||||
mockFrenchEntry,
|
||||
mockRandomFileNameEntry,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should filter based on multiple rules (must match all rules)', () => {
|
||||
// File names containing the word file (case insensitive)
|
||||
expect(
|
||||
filterEntries(entries, [{ pattern: '[fF][iI][lL][eE]' }, { pattern: 'some' }]),
|
||||
).toEqual([mockRandomFileNameEntry]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('combined field and file rule', () => {
|
||||
it('should filter based on multiple rules (must match all rules)', () => {
|
||||
expect(
|
||||
filterEntries(entries, [{ pattern: 'index.md$' }, { field: 'tags', value: 'tag-3' }]),
|
||||
).toEqual([mockUnderscoreIndexEntry]);
|
||||
});
|
||||
});
|
||||
});
|
54
packages/core/src/lib/util/filter.util.ts
Normal file
54
packages/core/src/lib/util/filter.util.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { parse } from 'path';
|
||||
|
||||
import type { Entry, FieldFilterRule, FilterRule } from '@staticcms/core/interface';
|
||||
|
||||
function entryMatchesFieldRule(entry: Entry, filterRule: FieldFilterRule): boolean {
|
||||
const fieldValue = entry.data?.[filterRule.field];
|
||||
if ('pattern' in filterRule) {
|
||||
if (Array.isArray(fieldValue)) {
|
||||
return Boolean(fieldValue.find(v => new RegExp(filterRule.pattern).test(String(v))));
|
||||
}
|
||||
|
||||
return new RegExp(filterRule.pattern).test(String(fieldValue));
|
||||
}
|
||||
|
||||
if (Array.isArray(fieldValue)) {
|
||||
if (Array.isArray(filterRule.value)) {
|
||||
if (filterRule.matchAll) {
|
||||
return Boolean(filterRule.value.every(ruleValue => fieldValue.includes(ruleValue)));
|
||||
}
|
||||
|
||||
return Boolean(fieldValue.find(v => filterRule.value.includes(String(v))));
|
||||
}
|
||||
|
||||
return fieldValue.includes(filterRule.value);
|
||||
}
|
||||
|
||||
if (Array.isArray(filterRule.value)) {
|
||||
if (filterRule.matchAll) {
|
||||
return Boolean(filterRule.value.every(ruleValue => fieldValue === ruleValue));
|
||||
}
|
||||
|
||||
return filterRule.value.includes(String(fieldValue));
|
||||
}
|
||||
|
||||
return fieldValue === filterRule.value;
|
||||
}
|
||||
|
||||
function entryMatchesRule(entry: Entry, filterRule: FilterRule) {
|
||||
if ('field' in filterRule) {
|
||||
return entryMatchesFieldRule(entry, filterRule);
|
||||
}
|
||||
|
||||
return new RegExp(filterRule.pattern).test(parse(entry.path).base);
|
||||
}
|
||||
|
||||
export default function filterEntries(entries: Entry[], filterRule: FilterRule | FilterRule[]) {
|
||||
return entries.filter(entry => {
|
||||
if (Array.isArray(filterRule)) {
|
||||
return filterRule.every(r => entryMatchesRule(entry, r));
|
||||
}
|
||||
|
||||
return entryMatchesRule(entry, filterRule);
|
||||
});
|
||||
}
|
@ -6,30 +6,30 @@ weight: 9
|
||||
|
||||
`collections` accepts a list of collection objects, each with the following options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | string | | Unique identifier for the collection, used as the key when referenced in other contexts (like the [relation widget](/docs/widgets/#relation)) |
|
||||
| identifier_field | string | `'title'` | _Optional_. See [identifier_field](#identifier_field) below |
|
||||
| label | string | `name` | _Optional_. Label for the collection in the editor UI |
|
||||
| label_singular | string | `label` | _Optional_. Singular label for certain elements in the editor |
|
||||
| icon | string | | _Optional_. Unique name of icon to use in main menu. See [Custom Icons](/docs/custom-icons) |
|
||||
| description | string | | _Optional_. Text displayed below the label when viewing a collection |
|
||||
| files or folder | [Collection Files](/docs/collection-types#file-collections)<br />\| [Collection Folder](/docs/collection-types#folder-collections) | | **Requires one of these**: Specifies the collection type and location; details in [Collection Types](/docs/collection-types) |
|
||||
| filter | FilterRule | | _Optional_. Filter for [Folder Collections](/docs/collection-types#folder-collections) |
|
||||
| create | boolean | `false` | _Optional_. **For [Folder Collections](/docs/collection-types#folder-collections) only**<br />`true` - Allows users to create new items in the collection |
|
||||
| hide | boolean | `false` | _Optional_. `true` hides a collection in the Static CMS UI. Useful when using the relation widget to hide referenced collections |
|
||||
| delete | boolean | `true` | _Optional_. `false` prevents users from deleting items in a collection |
|
||||
| extension | string | | _Optional_. See [extension](#extension-and-format) below |
|
||||
| format | 'yaml'<br />\| 'yml'<br />\| 'json'<br />\| 'frontmatter'<br />\| 'json-frontmatter'<br />\| 'yaml-frontmatter' | | _Optional_. See [format](#extension-and-format) below |
|
||||
| frontmatter_delimiter | string<br />\| [string, string] | | _Optional_. See [frontmatter_delimiter](#frontmatter_delimiter) below |
|
||||
| slug | string | | _Optional_. See [slug](#slug) below |
|
||||
| fields (required) | Field | | _Optional_. See [fields](#fields) below. Ignored if [Files Collection](/docs/collection-types#file-collections) |
|
||||
| editor | EditorConfig | | _Optional_. See [editor](#editor) below |
|
||||
| summary | string | | _Optional_. See [summary](#summary) below |
|
||||
| summary_fields | list of strings | ['summary'] | _Optional_. A list of fields to show in the table view |
|
||||
| sortable_fields | SortableFields | | _Optional_. See [sortable_fields](#sortable_fields) below |
|
||||
| view_filters | ViewFilter | | _Optional_. See [view_filters](#view_filters) below |
|
||||
| view_groups | ViewGroup | | _Optional_. See [view_groups](#view_groups) below |
|
||||
| Name | Type | Default | Description |
|
||||
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | string | | Unique identifier for the collection, used as the key when referenced in other contexts (like the [relation widget](/docs/widgets/#relation)) |
|
||||
| identifier_field | string | `'title'` | _Optional_. See [identifier field](#identifier-field) below |
|
||||
| label | string | `name` | _Optional_. Label for the collection in the editor UI |
|
||||
| label_singular | string | `label` | _Optional_. Singular label for certain elements in the editor |
|
||||
| icon | string | | _Optional_. Unique name of icon to use in main menu. See [custom icons](/docs/custom-icons) |
|
||||
| description | string | | _Optional_. Text displayed below the label when viewing a collection |
|
||||
| files or folder | [Collection Files](/docs/collection-types#file-collections)<br />\| [Collection Folder](/docs/collection-types#folder-collections) | | **Requires one of these**: Specifies the collection type and location; details in [collection types](/docs/collection-types) |
|
||||
| filter | FilterRule<br />\| List of FilterRules | | _Optional_. Field and file filter for [Folder Collections](/docs/collection-types#folder-collections). See [filtered folder collections](/docs/collection-types#filtered-folder-collections) |
|
||||
| create | boolean | `false` | _Optional_. **For [Folder Collections](/docs/collection-types#folder-collections) only**<br />`true` - Allows users to create new items in the collection |
|
||||
| hide | boolean | `false` | _Optional_. `true` hides a collection in the Static CMS UI. Useful when using the relation widget to hide referenced collections |
|
||||
| delete | boolean | `true` | _Optional_. `false` prevents users from deleting items in a collection |
|
||||
| extension | string | | _Optional_. See [extension and format](#extension-and-format) below |
|
||||
| format | 'yaml'<br />\| 'yml'<br />\| 'json'<br />\| 'frontmatter'<br />\| 'json-frontmatter'<br />\| 'yaml-frontmatter' | | _Optional_. See [extension and format](#extension-and-format) below |
|
||||
| frontmatter_delimiter | string<br />\| [string, string] | | _Optional_. See [frontmatter delimiter](#frontmatter-delimiter) below |
|
||||
| slug | string | | _Optional_. See [slug](#slug) below |
|
||||
| fields (required) | Field | | _Optional_. See [fields](#fields) below. Ignored if [Files Collection](/docs/collection-types#file-collections) |
|
||||
| editor | EditorConfig | | _Optional_. See [editor](#editor) below |
|
||||
| summary | string | | _Optional_. See [summary](#summary) below |
|
||||
| summary_fields | list of strings | ['summary'] | _Optional_. A list of fields to show in the table view |
|
||||
| sortable_fields | SortableFields | | _Optional_. See [sortable fields](#sortable-fields) below |
|
||||
| view_filters | ViewFilter | | _Optional_. See [view filters](#view-filters) below |
|
||||
| view_groups | ViewGroup | | _Optional_. See [view groups](#view-groups) below |
|
||||
|
||||
## Identifier Field
|
||||
|
||||
|
@ -105,12 +105,20 @@ collections: [
|
||||
|
||||
### Filtered folder collections
|
||||
|
||||
The entries for any folder collection can be filtered based on the value of a single field. By filtering a folder into different collections, you can manage files with different fields, options, extensions, etc. in the same folder.
|
||||
The entries for any folder collection can be filtered based on the values of the fields or on file names. By filtering a folder into different collections, you can manage files with different fields, options, extensions, etc. in the same folder.
|
||||
|
||||
The `filter` option requires two fields:
|
||||
The `filter` option can take a single filter rule or a list of filter rules. There are two types of filter rules available: field and file.
|
||||
|
||||
- `field`: The name of the collection field to filter on.
|
||||
- `value`: The desired field value.
|
||||
#### Field Filter Rule
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| -------- | ----------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| field | string | | The name of one of the fields in the collection's `fields` |
|
||||
| value | string<br />\|list of strings | | _Optional_. The desired value or values to match. Required if no `pattern` provided. Ignored if `pattern` is provided |
|
||||
| pattern | regular expression | | _Optional_. A regex pattern to match against the field's value |
|
||||
| matchAll | boolean | `false` | _Optional_. _Ignored if value is not a list of strings_<br /><ul><li>`true` - The field's values must include or match all of the filter rule's values</li><li>`false` - The field's value must include or match only one of the filter rule's values</li></ul> |
|
||||
|
||||
##### Filtered by Language
|
||||
|
||||
The example below creates two collections in the same folder, filtered by the `language` field. The first collection includes posts with `language: en`, and the second, with `language: es`.
|
||||
|
||||
@ -129,6 +137,7 @@ collections:
|
||||
label: Language
|
||||
widget: select
|
||||
options: ['en', 'es']
|
||||
default: 'en'
|
||||
- name: title
|
||||
label: Title
|
||||
widget: string
|
||||
@ -147,6 +156,7 @@ collections:
|
||||
label: Lenguaje
|
||||
widget: select
|
||||
options: ['en', 'es']
|
||||
default: 'es'
|
||||
- name: title
|
||||
label: Titulo
|
||||
widget: string
|
||||
@ -162,11 +172,28 @@ collections: [
|
||||
label: 'Blog in English',
|
||||
folder: '_posts',
|
||||
create: true,
|
||||
filter: { field: 'language', value: 'en' },
|
||||
filter: {
|
||||
field: 'language',
|
||||
value: 'en',
|
||||
},
|
||||
fields: [
|
||||
{ name: 'language', label: 'Language', widget: 'select', options: ['en', 'es'] },
|
||||
{ name: 'title', label: 'Title', widget: 'string' },
|
||||
{ name: 'body', label: 'Content', widget: 'markdown' },
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
widget: 'select',
|
||||
options: ['en', 'es'],
|
||||
default: 'en',
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
label: 'Content',
|
||||
widget: 'markdown',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -174,11 +201,196 @@ collections: [
|
||||
label: 'Blog en Español',
|
||||
folder: '_posts',
|
||||
create: true,
|
||||
filter: { field: 'language', value: 'es' },
|
||||
filter: {
|
||||
field: 'language',
|
||||
value: 'es',
|
||||
},
|
||||
fields: [
|
||||
{ name: 'language', label: 'Lenguaje', widget: 'select', options: ['en', 'es'] },
|
||||
{ name: 'title', label: 'Titulo', widget: 'string' },
|
||||
{ name: 'body', label: 'Contenido', widget: 'markdown' },
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Lenguaje',
|
||||
widget: 'select',
|
||||
options: ['en', 'es'],
|
||||
default: 'es',
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Titulo',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
label: 'Contenido',
|
||||
widget: 'markdown',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
##### Filtered by Tags
|
||||
|
||||
The example below creates two collections in the same folder, filtered by the `tags` field. The first collection includes posts with the `news` or `article` tags, and the second, with the `blog` tag.
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
collections:
|
||||
- name: 'news'
|
||||
label: 'News'
|
||||
folder: '_posts'
|
||||
create: true
|
||||
filter:
|
||||
field: tags
|
||||
value:
|
||||
- news
|
||||
- article
|
||||
fields:
|
||||
- name: tags
|
||||
label: Tags
|
||||
widget: list
|
||||
default:
|
||||
- news
|
||||
- name: title
|
||||
label: Title
|
||||
widget: string
|
||||
- name: body
|
||||
label: Content
|
||||
widget: markdown
|
||||
- name: blogs
|
||||
label: 'Blogs'
|
||||
folder: _posts
|
||||
create: true
|
||||
filter:
|
||||
field: tags
|
||||
value: blog
|
||||
fields:
|
||||
- name: tags
|
||||
label: Tags
|
||||
widget: list
|
||||
default:
|
||||
- blog
|
||||
- name: title
|
||||
label: Title
|
||||
widget: string
|
||||
- name: body
|
||||
label: Content
|
||||
widget: markdown
|
||||
```
|
||||
|
||||
```js
|
||||
collections: [
|
||||
{
|
||||
name: 'news',
|
||||
label: 'News',
|
||||
folder: '_posts',
|
||||
create: true,
|
||||
filter: {
|
||||
field: 'tags',
|
||||
value: ['news', 'article'],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'tags',
|
||||
label: 'Tags',
|
||||
widget: 'list',
|
||||
default: ['news'],
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
label: 'Content',
|
||||
widget: 'markdown',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'blogs',
|
||||
label: 'Blogs',
|
||||
folder: '_posts',
|
||||
create: true,
|
||||
filter: {
|
||||
field: 'tags',
|
||||
value: 'blog',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'tags',
|
||||
label: 'Tags',
|
||||
widget: 'list',
|
||||
default: ['blog'],
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
label: 'Content',
|
||||
widget: 'markdown',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
#### File Name Filter Rule
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------- | ------------------ | ------- | ------------------------------------------------------ |
|
||||
| pattern | regular expression | | A regex pattern to match against the entry's file name |
|
||||
|
||||
##### Filtered by Tags
|
||||
|
||||
The example below creates a collection containing only files named `index.md` exactly.
|
||||
|
||||
<CodeTabs>
|
||||
```yaml
|
||||
collections:
|
||||
- name: 'posts'
|
||||
label: 'Posts'
|
||||
folder: '_posts'
|
||||
create: true
|
||||
filter:
|
||||
pattern: '^index.md$'
|
||||
fields:
|
||||
- name: title
|
||||
label: Title
|
||||
widget: string
|
||||
- name: body
|
||||
label: Content
|
||||
widget: markdown
|
||||
```
|
||||
|
||||
```js
|
||||
collections: [
|
||||
{
|
||||
name: 'posts',
|
||||
label: 'Posts',
|
||||
folder: '_posts',
|
||||
create: true,
|
||||
filter: {
|
||||
pattern: '^index.md$',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
label: 'Content',
|
||||
widget: 'markdown',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user