From 6b9402d593d6702fb8dc73699d2cdc15705762ad Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 15 Sep 2023 17:59:53 +0200 Subject: [PATCH] #563 - Implementation of the fieldCollection --- CHANGELOG.md | 2 + package.json | 292 +++++++++++++++---------------- package.nls.json | 2 +- src/helpers/ArticleHelper.ts | 29 +-- src/helpers/ContentType.ts | 45 ++++- src/helpers/DashboardSettings.ts | 3 +- src/helpers/PanelSettings.ts | 4 +- 7 files changed, 190 insertions(+), 187 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c6fb60b..f2ba2ce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### ✨ New features +- [#563](https://github.com/estruyf/vscode-front-matter/issues/563): New `fieldCollection` to inherit/reuse fields in multiple content-types + ### 🎨 Enhancements - [#638](https://github.com/estruyf/vscode-front-matter/issues/638): Add Hexo support for the `_drafts` folder diff --git a/package.json b/package.json index 0da0ce09..cdc51460 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,7 @@ "color": "#0e131f", "theme": "dark" }, - "badges": [ - { + "badges": [{ "description": "version", "url": "https://img.shields.io/github/package-json/v/estruyf/vscode-front-matter?color=green&label=vscode-front-matter&style=flat-square", "href": "https://github.com/estruyf/vscode-front-matter" @@ -71,8 +70,7 @@ "**/.frontmatter/config/*.json": "jsonc" } }, - "keybindings": [ - { + "keybindings": [{ "command": "frontMatter.dashboard", "key": "alt+d" }, @@ -90,24 +88,20 @@ } ], "viewsContainers": { - "activitybar": [ - { - "id": "frontmatter-explorer", - "title": "Front Matter", - "icon": "assets/frontmatter-short-min.svg" - } - ] + "activitybar": [{ + "id": "frontmatter-explorer", + "title": "Front Matter", + "icon": "assets/frontmatter-short-min.svg" + }] }, "views": { - "frontmatter-explorer": [ - { - "id": "frontMatter.explorer", - "name": "Front Matter", - "icon": "assets/frontmatter-short-min.svg", - "contextualTitle": "Front Matter", - "type": "webview" - } - ] + "frontmatter-explorer": [{ + "id": "frontMatter.explorer", + "name": "Front Matter", + "icon": "assets/frontmatter-short-min.svg", + "contextualTitle": "Front Matter", + "type": "webview" + }] }, "configuration": { "title": "%settings.configuration.title%", @@ -170,8 +164,7 @@ "frontMatter.content.defaultFileType": { "type": "string", "default": "md", - "oneOf": [ - { + "oneOf": [{ "enum": [ "md", "mdx" @@ -187,8 +180,7 @@ "frontMatter.content.defaultSorting": { "type": "string", "default": "", - "oneOf": [ - { + "oneOf": [{ "enum": [ "LastModifiedAsc", "LastModifiedDesc", @@ -535,8 +527,7 @@ "command": { "$id": "#scriptCommand", "type": "string", - "anyOf": [ - { + "anyOf": [{ "enum": [ "node", "bash", @@ -736,8 +727,7 @@ "title", "file" ], - "anyOf": [ - { + "anyOf": [{ "required": [ "schema" ] @@ -791,8 +781,7 @@ "id", "path" ], - "anyOf": [ - { + "anyOf": [{ "required": [ "schema" ] @@ -1085,7 +1074,8 @@ "divider", "heading", "customField", - "contentRelationship" + "contentRelationship", + "fieldCollection" ], "description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.type.description%" }, @@ -1165,8 +1155,7 @@ "default": "", "description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.taxonomyId.description%", "not": { - "anyOf": [ - { + "anyOf": [{ "const": "" }, { @@ -1355,8 +1344,7 @@ "type", "name" ], - "allOf": [ - { + "allOf": [{ "if": { "properties": { "type": { @@ -1483,6 +1471,20 @@ ] } }, + { + "if": { + "properties": { + "type": { + "const": "fieldCollection" + } + } + }, + "then": { + "required": [ + "fieldGroup" + ] + } + }, { "if": { "properties": { @@ -1542,51 +1544,48 @@ "fields" ] }, - "default": [ - { - "name": "default", - "pageBundle": false, - "fields": [ - { - "title": "Title", - "name": "title", - "type": "string" - }, - { - "title": "Description", - "name": "description", - "type": "string" - }, - { - "title": "Publishing date", - "name": "date", - "type": "datetime", - "default": "{{now}}", - "isPublishDate": true - }, - { - "title": "Content preview", - "name": "preview", - "type": "image" - }, - { - "title": "Is in draft", - "name": "draft", - "type": "boolean" - }, - { - "title": "Tags", - "name": "tags", - "type": "tags" - }, - { - "title": "Categories", - "name": "categories", - "type": "categories" - } - ] - } - ], + "default": [{ + "name": "default", + "pageBundle": false, + "fields": [{ + "title": "Title", + "name": "title", + "type": "string" + }, + { + "title": "Description", + "name": "description", + "type": "string" + }, + { + "title": "Publishing date", + "name": "date", + "type": "datetime", + "default": "{{now}}", + "isPublishDate": true + }, + { + "title": "Content preview", + "name": "preview", + "type": "image" + }, + { + "title": "Is in draft", + "name": "draft", + "type": "boolean" + }, + { + "title": "Tags", + "name": "tags", + "type": "tags" + }, + { + "title": "Categories", + "name": "categories", + "type": "categories" + } + ] + }], "scope": "Taxonomy" }, "frontMatter.taxonomy.customTaxonomy": { @@ -1599,8 +1598,7 @@ "type": "string", "description": "%setting.frontMatter.taxonomy.customTaxonomy.items.properties.id.description%", "not": { - "anyOf": [ - { + "anyOf": [{ "const": "" }, { @@ -1786,8 +1784,7 @@ } } }, - "commands": [ - { + "commands": [{ "command": "frontMatter.project.switch", "title": "%command.frontMatter.project.switch%", "category": "Front Matter", @@ -2122,15 +2119,12 @@ "category": "Front Matter" } ], - "submenus": [ - { - "id": "frontmatter.submenu", - "label": "Front Matter" - } - ], + "submenus": [{ + "id": "frontmatter.submenu", + "label": "Front Matter" + }], "menus": { - "editor/title": [ - { + "editor/title": [{ "command": "frontMatter.markup.heading", "group": "navigation@-133", "when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg" @@ -2211,14 +2205,11 @@ "when": "resourceFilename == 'frontmatter.json'" } ], - "explorer/context": [ - { - "submenu": "frontmatter.submenu", - "group": "frontmatter@1" - } - ], - "frontmatter.submenu": [ - { + "explorer/context": [{ + "submenu": "frontmatter.submenu", + "group": "frontmatter@1" + }], + "frontmatter.submenu": [{ "command": "frontMatter.createFromTemplate", "when": "explorerResourceIsFolder", "group": "frontmatter@1" @@ -2234,8 +2225,7 @@ "group": "frontmatter@3" } ], - "commandPalette": [ - { + "commandPalette": [{ "command": "frontMatter.init", "when": "frontMatterCanInit" }, @@ -2380,8 +2370,7 @@ "when": "frontMatter:file:isValid == true" } ], - "view/title": [ - { + "view/title": [{ "command": "frontMatter.chatbot", "group": "navigation@0", "when": "view == frontMatter.explorer" @@ -2412,57 +2401,52 @@ } ] }, - "grammars": [ - { - "path": "./syntaxes/hugo.tmLanguage.json", - "scopeName": "frontmatter.markdown.hugo", - "injectTo": [ - "text.html.markdown" - ] - } - ], - "walkthroughs": [ - { - "id": "frontmatter.welcome", - "title": "Get started with Front Matter", - "description": "Discover the features of Front Matter and learn how to use the CMS for your SSG or static site.", - "steps": [ - { - "id": "frontmatter.welcome.init", - "title": "Get started", - "description": "Initial steps to get started.\n[Open dashboard](command:frontMatter.dashboard)", - "media": { - "markdown": "assets/walkthrough/get-started.md" - }, - "completionEvents": [ - "onContext:frontMatterInitialized" - ] + "grammars": [{ + "path": "./syntaxes/hugo.tmLanguage.json", + "scopeName": "frontmatter.markdown.hugo", + "injectTo": [ + "text.html.markdown" + ] + }], + "walkthroughs": [{ + "id": "frontmatter.welcome", + "title": "Get started with Front Matter", + "description": "Discover the features of Front Matter and learn how to use the CMS for your SSG or static site.", + "steps": [{ + "id": "frontmatter.welcome.init", + "title": "Get started", + "description": "Initial steps to get started.\n[Open dashboard](command:frontMatter.dashboard)", + "media": { + "markdown": "assets/walkthrough/get-started.md" }, - { - "id": "frontmatter.welcome.documentation", - "title": "Documentation", - "description": "Check out the documentation for Front Matter.\n[View our documentation](https://frontmatter.codes/docs)", - "media": { - "markdown": "assets/walkthrough/documentation.md" - }, - "completionEvents": [ - "onLink:https://frontmatter.codes/docs" - ] + "completionEvents": [ + "onContext:frontMatterInitialized" + ] + }, + { + "id": "frontmatter.welcome.documentation", + "title": "Documentation", + "description": "Check out the documentation for Front Matter.\n[View our documentation](https://frontmatter.codes/docs)", + "media": { + "markdown": "assets/walkthrough/documentation.md" }, - { - "id": "frontmatter.welcome.supporter", - "title": "Support the project", - "description": "Become a supporter.\n[Support the project](https://github.com/sponsors/estruyf)", - "media": { - "markdown": "assets/walkthrough/support-the-project.md" - }, - "completionEvents": [ - "onLink:https://github.com/sponsors/estruyf" - ] - } - ] - } - ] + "completionEvents": [ + "onLink:https://frontmatter.codes/docs" + ] + }, + { + "id": "frontmatter.welcome.supporter", + "title": "Support the project", + "description": "Become a supporter.\n[Support the project](https://github.com/sponsors/estruyf)", + "media": { + "markdown": "assets/walkthrough/support-the-project.md" + }, + "completionEvents": [ + "onLink:https://github.com/sponsors/estruyf" + ] + } + ] + }] }, "scripts": { "dev:ext": "npm run clean && npm run localization:generate && npm-run-all --parallel watch:*", @@ -2597,4 +2581,4 @@ "vsce": { "dependencies": false } -} +} \ No newline at end of file diff --git a/package.nls.json b/package.nls.json index 4789a27f..f69ab838 100644 --- a/package.nls.json +++ b/package.nls.json @@ -215,7 +215,7 @@ "setting.frontMatter.taxonomy.customTaxonomy.items.properties.options.description": "Options from which you can pick.", "setting.frontMatter.taxonomy.dateField.markdownDescription": "This setting is used to define the publishing date field of your articles. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.datefield)", "setting.frontMatter.taxonomy.dateFormat.markdownDescription": "Specify the date format for your articles. Check [date-fns formating](https://date-fns.org/v2.0.1/docs/format) for more information. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.dateformat)", - "setting.frontMatter.taxonomy.fieldGroups.markdownDescription": "Define the field groups you want to use for your block fields. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.fieldgroups)", + "setting.frontMatter.taxonomy.fieldGroups.markdownDescription": "Define the field groups you want to use for your block fields or collection fields. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.fieldgroups)", "setting.frontMatter.taxonomy.fieldGroups.items.properties.id.description": "The name of the field group", "setting.frontMatter.taxonomy.fieldGroups.items.properties.labelField.description": "The name of the field to be used as display value", "setting.frontMatter.taxonomy.frontMatterType.markdownDescription": "Specify the type of Front Matter to use. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.frontmattertype)", diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index 2b2749ed..0e357dfb 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -331,34 +331,7 @@ export class ArticleHelper { contentType.fields = DEFAULT_CONTENT_TYPE.fields; } - // Check if there is a field collection - const fcFields = ContentType.findAllFieldsByType(contentType.fields || [], 'fieldCollection'); - - if (fcFields.length > 0) { - const fieldCollections = Settings.get('taxonomy.fieldCollection'); - - if (fieldCollections && fieldCollections.length > 0) { - for (const cField of fcFields) { - let fields = contentType.fields; - - for (const fieldName of cField) { - const field = fields.find((f) => f.name === fieldName); - - if (field && field.type === 'fieldCollection') { - const fieldCollection = fieldCollections.find( - (fc) => fc.id === (field as any).fieldCollectionId - ); - if (fieldCollection) { - const fieldIdx = fields.findIndex((f) => f.name === field.name); - fields.splice(fieldIdx, 1, ...fieldCollection.fields); - } - } else if (field && field.type === 'fields') { - fields = field.fields || []; - } - } - } - } - } + contentType.fields = ContentType.mergeFields(contentType.fields); return contentType; } diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index 10c59606..9078276e 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -111,7 +111,50 @@ export class ContentType { * @returns */ public static getAll() { - return Settings.get(SETTING_TAXONOMY_CONTENT_TYPES); + const cts = Settings.get(SETTING_TAXONOMY_CONTENT_TYPES); + + for (const ct of cts || []) { + ct.fields = ContentType.mergeFields(ct.fields || []); + } + + return cts; + } + + /** + * Merge the collection fields + * @param contentType + * @returns + */ + public static mergeFields(fields: Field[]) { + if (!fields) { + return []; + } + + // Check if there is a field collection + const fcFields = ContentType.findAllFieldsByType(fields || [], 'fieldCollection'); + if (fcFields.length > 0) { + const fieldGroups = Settings.get(SETTING_TAXONOMY_FIELD_GROUPS); + + if (fieldGroups && fieldGroups.length > 0) { + for (const cField of fcFields) { + for (const fieldName of cField) { + const field = fields.find((f) => f.name === fieldName); + + if (field && field.type === 'fieldCollection') { + const fieldGroup = fieldGroups.find((fg) => fg.id === field.fieldGroup); + if (fieldGroup) { + const fieldIdx = fields.findIndex((f) => f.name === field.name); + fields.splice(fieldIdx, 1, ...fieldGroup.fields); + } + } else if (field && field.type === 'fields') { + fields = field.fields || []; + } + } + } + } + } + + return fields; } /** diff --git a/src/helpers/DashboardSettings.ts b/src/helpers/DashboardSettings.ts index 6d1aaf6d..b8cb3ba3 100644 --- a/src/helpers/DashboardSettings.ts +++ b/src/helpers/DashboardSettings.ts @@ -46,6 +46,7 @@ import { FrameworkDetector } from './FrameworkDetector'; import { Settings } from './SettingsHelper'; import { parseWinPath } from './parseWinPath'; import { TaxonomyHelper } from './TaxonomyHelper'; +import { ContentType } from './ContentType'; export class DashboardSettings { private static cachedSettings: ISettings | undefined = undefined; @@ -85,7 +86,7 @@ export class DashboardSettings { ExtensionState.PagesView, 'workspace' ), - contentTypes: Settings.get(SETTING_TAXONOMY_CONTENT_TYPES) || [], + contentTypes: ContentType.getAll() || [], draftField: Settings.get(SETTING_CONTENT_DRAFT_FIELD), customSorting: Settings.get(SETTING_CONTENT_SORTING), contentFolders: Folders.get(), diff --git a/src/helpers/PanelSettings.ts b/src/helpers/PanelSettings.ts index f60c634f..47906fee 100644 --- a/src/helpers/PanelSettings.ts +++ b/src/helpers/PanelSettings.ts @@ -1,6 +1,6 @@ import { SETTING_SPONSORS_AI_ENABLED, SETTING_WEBSITE_URL } from './../constants/settings'; import { workspace } from 'vscode'; -import { Extension, Settings, TaxonomyHelper } from '.'; +import { ContentType, Extension, Settings, TaxonomyHelper } from '.'; import { Dashboard } from '../commands/Dashboard'; import { Preview } from '../commands/Preview'; import { Project } from '../commands/Project'; @@ -83,7 +83,7 @@ export class PanelSettings { fmHighlighting: Settings.get(SETTING_CONTENT_FRONTMATTER_HIGHLIGHT), preview: Preview.getSettings(), commaSeparatedFields: Settings.get(SETTING_COMMA_SEPARATED_FIELDS) || [], - contentTypes: Settings.get(SETTING_TAXONOMY_CONTENT_TYPES) || [], + contentTypes: ContentType.getAll() || [], dashboardViewData: Dashboard.viewData, draftField: Settings.get(SETTING_CONTENT_DRAFT_FIELD), isBacker: await Extension.getInstance().getState(