feat: expanded folder collection filter support (#820)
This commit is contained in:
parent
85db6b4f8d
commit
061febfd02
@ -39,6 +39,7 @@ import {
|
|||||||
selectInferredField,
|
selectInferredField,
|
||||||
selectMediaFolders,
|
selectMediaFolders,
|
||||||
} from './lib/util/collection.util';
|
} from './lib/util/collection.util';
|
||||||
|
import filterEntries from './lib/util/filter.util';
|
||||||
import {
|
import {
|
||||||
DRAFT_MEDIA_FILES,
|
DRAFT_MEDIA_FILES,
|
||||||
selectMediaFilePath,
|
selectMediaFilePath,
|
||||||
@ -1020,15 +1021,8 @@ export class Backend<EF extends BaseField = UnknownField, BC extends BackendClas
|
|||||||
return file.fields.map(f => f.name);
|
return file.fields.map(f => f.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
filterEntries(collection: { entries: Entry[] }, filterRule: FilterRule) {
|
filterEntries(collection: { entries: Entry[] }, filterRule: FilterRule | FilterRule[]) {
|
||||||
return collection.entries.filter(entry => {
|
return filterEntries(collection.entries, filterRule);
|
||||||
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;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,11 +170,27 @@ export interface EntryDraft {
|
|||||||
fieldsErrors: FieldsErrors;
|
fieldsErrors: FieldsErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FilterRule {
|
export interface BaseFieldFilterRule {
|
||||||
value: string;
|
|
||||||
field: string;
|
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 {
|
export interface EditorConfig {
|
||||||
preview?: boolean;
|
preview?: boolean;
|
||||||
frame?: boolean;
|
frame?: boolean;
|
||||||
@ -224,7 +240,7 @@ export interface BaseCollection {
|
|||||||
isFetching?: boolean;
|
isFetching?: boolean;
|
||||||
summary?: string;
|
summary?: string;
|
||||||
summary_fields?: string[];
|
summary_fields?: string[];
|
||||||
filter?: FilterRule;
|
filter?: FilterRule | FilterRule[];
|
||||||
label_singular?: string;
|
label_singular?: string;
|
||||||
label: string;
|
label: string;
|
||||||
sortable_fields?: SortableFields;
|
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);
|
||||||
|
});
|
||||||
|
}
|
@ -7,29 +7,29 @@ weight: 9
|
|||||||
`collections` accepts a list of collection objects, each with the following options
|
`collections` accepts a list of collection objects, each with the following options
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| 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)) |
|
| 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 |
|
| identifier_field | string | `'title'` | _Optional_. See [identifier field](#identifier-field) below |
|
||||||
| label | string | `name` | _Optional_. Label for the collection in the editor UI |
|
| 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 |
|
| 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) |
|
| 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 |
|
| 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) |
|
| 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) |
|
| 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 |
|
| 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 |
|
| 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 |
|
| delete | boolean | `true` | _Optional_. `false` prevents users from deleting items in a collection |
|
||||||
| extension | string | | _Optional_. See [extension](#extension-and-format) below |
|
| 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 [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 |
|
| frontmatter_delimiter | string<br />\| [string, string] | | _Optional_. See [frontmatter delimiter](#frontmatter-delimiter) below |
|
||||||
| slug | string | | _Optional_. See [slug](#slug) 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) |
|
| fields (required) | Field | | _Optional_. See [fields](#fields) below. Ignored if [Files Collection](/docs/collection-types#file-collections) |
|
||||||
| editor | EditorConfig | | _Optional_. See [editor](#editor) below |
|
| editor | EditorConfig | | _Optional_. See [editor](#editor) below |
|
||||||
| summary | string | | _Optional_. See [summary](#summary) 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 |
|
| 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 |
|
| sortable_fields | SortableFields | | _Optional_. See [sortable fields](#sortable-fields) below |
|
||||||
| view_filters | ViewFilter | | _Optional_. See [view_filters](#view_filters) below |
|
| view_filters | ViewFilter | | _Optional_. See [view filters](#view-filters) below |
|
||||||
| view_groups | ViewGroup | | _Optional_. See [view_groups](#view_groups) below |
|
| view_groups | ViewGroup | | _Optional_. See [view groups](#view-groups) below |
|
||||||
|
|
||||||
## Identifier Field
|
## Identifier Field
|
||||||
|
|
||||||
|
@ -105,12 +105,20 @@ collections: [
|
|||||||
|
|
||||||
### Filtered folder 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.
|
#### Field Filter Rule
|
||||||
- `value`: The desired field value.
|
|
||||||
|
| 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`.
|
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
|
label: Language
|
||||||
widget: select
|
widget: select
|
||||||
options: ['en', 'es']
|
options: ['en', 'es']
|
||||||
|
default: 'en'
|
||||||
- name: title
|
- name: title
|
||||||
label: Title
|
label: Title
|
||||||
widget: string
|
widget: string
|
||||||
@ -147,6 +156,7 @@ collections:
|
|||||||
label: Lenguaje
|
label: Lenguaje
|
||||||
widget: select
|
widget: select
|
||||||
options: ['en', 'es']
|
options: ['en', 'es']
|
||||||
|
default: 'es'
|
||||||
- name: title
|
- name: title
|
||||||
label: Titulo
|
label: Titulo
|
||||||
widget: string
|
widget: string
|
||||||
@ -162,11 +172,28 @@ collections: [
|
|||||||
label: 'Blog in English',
|
label: 'Blog in English',
|
||||||
folder: '_posts',
|
folder: '_posts',
|
||||||
create: true,
|
create: true,
|
||||||
filter: { field: 'language', value: 'en' },
|
filter: {
|
||||||
|
field: 'language',
|
||||||
|
value: 'en',
|
||||||
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{ name: 'language', label: 'Language', widget: 'select', options: ['en', 'es'] },
|
{
|
||||||
{ name: 'title', label: 'Title', widget: 'string' },
|
name: 'language',
|
||||||
{ name: 'body', label: 'Content', widget: 'markdown' },
|
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',
|
label: 'Blog en Español',
|
||||||
folder: '_posts',
|
folder: '_posts',
|
||||||
create: true,
|
create: true,
|
||||||
filter: { field: 'language', value: 'es' },
|
filter: {
|
||||||
|
field: 'language',
|
||||||
|
value: 'es',
|
||||||
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{ name: 'language', label: 'Lenguaje', widget: 'select', options: ['en', 'es'] },
|
{
|
||||||
{ name: 'title', label: 'Titulo', widget: 'string' },
|
name: 'language',
|
||||||
{ name: 'body', label: 'Contenido', widget: 'markdown' },
|
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