From 926203f506676913772480aac4f7fda29db93929 Mon Sep 17 00:00:00 2001 From: Martin Jagodic Date: Tue, 27 Aug 2024 15:35:02 +0200 Subject: [PATCH 01/10] fix: remove attempt to get a more comprehensive error --- packages/decap-cms-core/src/backend.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/decap-cms-core/src/backend.ts b/packages/decap-cms-core/src/backend.ts index bcb8881de045..5b44b095b037 100644 --- a/packages/decap-cms-core/src/backend.ts +++ b/packages/decap-cms-core/src/backend.ts @@ -1,4 +1,4 @@ -import { attempt, flatten, isError, uniq, trim, sortBy, get, set } from 'lodash'; +import { flatten, isError, uniq, trim, sortBy, get, set } from 'lodash'; import { List, fromJS, Set } from 'immutable'; import * as fuzzy from 'fuzzy'; import { @@ -869,7 +869,7 @@ export class Backend { return (entry: EntryValue): EntryValue => { const format = resolveFormat(collection, entry); if (entry && entry.raw !== undefined) { - const data = (format && attempt(format.fromFile.bind(format, entry.raw))) || {}; + const data = (format && format.fromFile.bind(format, entry.raw)()) || {}; if (isError(data)) console.error(data); return Object.assign(entry, { data: isError(data) ? {} : data }); } From 8229ed7697b28cc88fcd3023e0e6381b20ef6a64 Mon Sep 17 00:00:00 2001 From: Anze Demsar Date: Wed, 4 Sep 2024 13:55:36 +0200 Subject: [PATCH 02/10] feat(): toast warnings for duplicate keys when loading entrties - wip suggestion --- .../decap-cms-core/src/actions/entries.ts | 16 ++++++++++++- packages/decap-cms-core/src/backend.ts | 24 ++++++++++++++----- .../decap-cms-core/src/valueObjects/Entry.ts | 1 + packages/decap-cms-locales/src/en/index.js | 1 + 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/packages/decap-cms-core/src/actions/entries.ts b/packages/decap-cms-core/src/actions/entries.ts index d7971b854d06..7dfe87f999cc 100644 --- a/packages/decap-cms-core/src/actions/entries.ts +++ b/packages/decap-cms-core/src/actions/entries.ts @@ -595,9 +595,10 @@ export function loadEntries(collection: Collection, page = 0) { cursor: Cursor; pagination: number; entries: EntryValue[]; + errors?: string[]; } = await (loadAllEntries ? // nested collections require all entries to construct the tree - provider.listAllEntries(collection).then((entries: EntryValue[]) => ({ entries })) + provider.listAllEntries(collection) : provider.listEntries(collection, page)); response = { ...response, @@ -616,6 +617,19 @@ export function loadEntries(collection: Collection, page = 0) { : Cursor.create(response.cursor), }; + response.errors?.forEach(error => { + dispatch( + addNotification({ + message: { + details: error, + key: 'ui.toast.duplicateFrontmatterKey', + }, + type: 'warning', + dismissAfter: 8000, + }), + ); + }); + dispatch( entriesLoaded( collection, diff --git a/packages/decap-cms-core/src/backend.ts b/packages/decap-cms-core/src/backend.ts index 5b44b095b037..f2c1a274c6e5 100644 --- a/packages/decap-cms-core/src/backend.ts +++ b/packages/decap-cms-core/src/backend.ts @@ -1,4 +1,4 @@ -import { flatten, isError, uniq, trim, sortBy, get, set } from 'lodash'; +import { flatten, isError, uniq, trim, sortBy, get, set, attempt } from 'lodash'; import { List, fromJS, Set } from 'immutable'; import * as fuzzy from 'fuzzy'; import { @@ -515,6 +515,7 @@ export class Backend { ), ); const formattedEntries = entries.map(this.entryWithFormat(collection)); + // todo: find error somewhere here and put it to errors array // If this collection has a "filter" property, filter entries accordingly const collectionFilter = collection.get('filter'); const filteredEntries = collectionFilter @@ -526,7 +527,7 @@ export class Backend { const groupedEntries = groupEntries(collection, extension, filteredEntries); return groupedEntries; } - + // todo: return object { entries, errors } + change all other processEntries uses to just take entries return filteredEntries; } @@ -567,10 +568,14 @@ export class Backend { cursorType: 'collectionEntries', collection, }); + return { entries: this.processEntries(loadedEntries, collection), pagination: cursor.meta?.get('page'), cursor, + errors: [ + 'error found in process entries' + ] }; } @@ -594,14 +599,17 @@ export class Backend { } const response = await this.listEntries(collection); - const { entries } = response; + const { entries, errors } = response; let { cursor } = response; while (cursor && cursor.actions!.includes('next')) { const { entries: newEntries, cursor: newCursor } = await this.traverseCursor(cursor, 'next'); entries.push(...newEntries); cursor = newCursor; } - return entries; + return { + entries, + errors, + }; } async search(collections: Collection[], searchTerm: string) { @@ -869,8 +877,12 @@ export class Backend { return (entry: EntryValue): EntryValue => { const format = resolveFormat(collection, entry); if (entry && entry.raw !== undefined) { - const data = (format && format.fromFile.bind(format, entry.raw)()) || {}; - if (isError(data)) console.error(data); + const data = (format && attempt(format.fromFile.bind(format, entry.raw))) || {}; + // const data = (format && format.fromFile.bind(format, entry.raw)()) || {}; + if (isError(data)) { + entry = Object.assign(entry, { parseError: data.message }); + } + return Object.assign(entry, { data: isError(data) ? {} : data }); } return format.fromFile(entry); diff --git a/packages/decap-cms-core/src/valueObjects/Entry.ts b/packages/decap-cms-core/src/valueObjects/Entry.ts index 6507215ec594..22c15322dd0f 100644 --- a/packages/decap-cms-core/src/valueObjects/Entry.ts +++ b/packages/decap-cms-core/src/valueObjects/Entry.ts @@ -35,6 +35,7 @@ export interface EntryValue { updatedOn: string; status?: string; meta: { path?: string }; + parseError?: string; i18n?: { // eslint-disable-next-line @typescript-eslint/no-explicit-any [locale: string]: any; diff --git a/packages/decap-cms-locales/src/en/index.js b/packages/decap-cms-locales/src/en/index.js index 5cba0d853d43..e7661a454c9d 100644 --- a/packages/decap-cms-locales/src/en/index.js +++ b/packages/decap-cms-locales/src/en/index.js @@ -271,6 +271,7 @@ const en = { onFailToDelete: 'Failed to delete entry: %{details}', onFailToUpdateStatus: 'Failed to update status: %{details}', missingRequiredField: "Oops, you've missed a required field. Please complete before saving.", + duplicateFrontmatterKey: 'Duplicate key found in frontmatter %{details}', entrySaved: 'Entry saved', entryPublished: 'Entry published', entryUnpublished: 'Entry unpublished', From 8911cad64bccb96349b64c635331b7c8dd95e79a Mon Sep 17 00:00:00 2001 From: Martin Jagodic Date: Wed, 4 Sep 2024 15:01:43 +0200 Subject: [PATCH 03/10] feat: try/catch formattedEntries --- dev-test/config.yml | 680 +++++++++++++++---------- packages/decap-cms-core/src/backend.ts | 32 +- 2 files changed, 434 insertions(+), 278 deletions(-) diff --git a/dev-test/config.yml b/dev-test/config.yml index d9bf6182a7cc..46e4142ce1f0 100644 --- a/dev-test/config.yml +++ b/dev-test/config.yml @@ -1,280 +1,424 @@ +local_backend: true + backend: - name: test-repo + name: git-gateway + branch: __BRANCH__ + squash_merges: true -site_url: https://example.com +display_url: https://www.grzs.si +logo_url: /media/brand/logo.png +media_folder: static/media/uploads +public_folder: /media/uploads -publish_mode: editorial_workflow -media_folder: assets/uploads +slug: + encoding: ascii + clean_accents: true +i18n: + structure: multiple_files + locales: [sl, en] -collections: # A list of collections the CMS should be able to edit - - name: 'posts' # Used in routes, ie.: /admin/collections/:slug/edit - label: 'Posts' # Used in the UI - label_singular: 'Post' # Used in the UI, ie: "New Post" - description: > - The description is a great place for tone setting, high level information, and editing - guidelines that are specific to a collection. - folder: '_posts' - slug: '{{year}}-{{month}}-{{day}}-{{slug}}' - summary: '{{title}} -- {{year}}/{{month}}/{{day}}' - create: true # Allow users to create new documents in this collection - view_filters: - - label: Posts With Index - field: title - pattern: 'This is post #' - - label: Posts Without Index - field: title - pattern: front matter post - - label: Drafts - field: draft - pattern: true - view_groups: - - label: Year - field: date - pattern: \d{4} - - label: Drafts - field: draft - fields: # The fields each document in this collection have - - { label: 'Title', name: 'title', widget: 'string', tagname: 'h1' } - - { label: 'Draft', name: 'draft', widget: 'boolean', default: false } - - { - label: 'Publish Date', - name: 'date', - widget: 'datetime', - format: 'YYYY-MM-DD HH:mm', - default: '{{now}}', - } - - label: 'Cover Image' - name: 'image' - widget: 'image' - required: false - tagname: '' +aliases: + - &TITLE {name: title, label: Title, widget: string, i18n: true} + - &DRAFT {name: draft, label: Draft, widget: boolean, required: false, i18n: true} + - &SLUG {name: slug, label: Slug, widget: string, required: false, i18n: true} + - &URL {name: url, label: URL, widget: string, required: false, i18n: true} + - &DESCRIPTION {label: Description, name: description, widget: text, i18n: true} + - &BODY {label: Content, name: body, widget: markdown, i18n: true} + - &DATE {label: Date, name: date, widget: datetime, i18n: duplicate} + - &GRS_UNIT {label: GRS Unit, name: unit, widget: string, required: false, i18n: duplicate} + - &AUTHOR {label: Author, name: author, widget: string, required: false, i18n: true} + - &TEASER {label: Teaser, name: teaser, widget: string, i18n: true} + - &TAGS {name: tags, widget: hidden, default: [article], i18n: duplicate} + - &LAYOUT {name: layout, widget: hidden, default: article, i18n: duplicate} + - &SHOW_FEATURED {label: Show featured image on page, name: showFeatured, i18n: duplicate, widget: select, options: ['false', 'true']} + - &FEATURED_IMAGE {label: Featured image, name: image, required: false, i18n: true, widget: object, fields: [ + {label: Source, name: src, widget: image, required: false, i18n: duplicate}, + {label: Text, name: alt, widget: string, required: false, i18n: true}, + ]} + - &BUTTON {name: button, i18n: true, widget: object, fields: [ + {name: href, widget: string, i18n: true}, + {name: text, widget: string, i18n: true}, + ]} + - &GALLERY {name: gallery, widget: list, required: false, i18n: true, fields: [ + {label: Image, name: src, widget: image, i18n: duplicate}, + {name: text, widget: string, required: false, i18n: true} + ]} + - &PAGE_FIELDS [ + *TITLE, + *URL, + *SHOW_FEATURED, + *FEATURED_IMAGE, + *BODY, + *GALLERY, + ] + - &HOME_FIELDS [ + *TITLE, + *DESCRIPTION, + {label: Gallery 1, name: "swipeGalleryTop", widget: list, fields: [ + {label: Image, name: src, widget: image}, + {name: text, widget: string}, + ]}, + {label: Gallery 2, name: swipeGalleryMiddle, widget: list, fields: [ + {label: Image, name: src, widget: image}, + {name: text, widget: string}, + ]}, + {label: Gallery 3, name: swipeGalleryBottom, widget: list, fields: [ + {label: Image, name: src, widget: image}, + {name: text, widget: string} + ]}, + {name: help, widget: object, fields: [ + {name: supertitle, widget: string}, + {name: title, widget: string}, + {name: text, widget: text}, + {name: topics, widget: list, fields: [ + {name: title, widget: string}, + ]}, + *BUTTON, + ]}, + {name: support, widget: object, fields: [ + {name: supertitle, widget: string}, + {name: title, widget: string}, + {name: text, widget: text}, + ]}, + {name: responsibility, widget: object, fields: [ + {name: title, widget: string}, + {name: links, widget: list, fields: [ + {name: title, widget: text}, + {name: desc, widget: text}, + {name: href, widget: string}, + ]}, + ]}, + {name: banner, widget: object, fields: [ + {name: href, widget: string, required: false}, + {name: title, widget: string, required: false}, + {name: srcMobile, label: mobile image, widget: image, required: false}, + {name: srcDesktop, label: destop image, widget: image, required: false}, + ]}, + {name: news, widget: object, fields: [ + {name: supertitle, widget: string, required: false}, + {name: title, widget: string}, + *BUTTON, + ]}, + {label: Slider, name: exposedContent, allow_add: true, widget: list, required: true, fields: [ + *TITLE, + {label: Description, name: desc, widget: string}, + {label: Link for button more, name: href, widget: string}, + {label: Order, name: weight, widget: number}, + ]} + ] + - &ABOUT_FIELDS [ + {name: foreword, widget: string}, + {label: Title, name: titleText, widget: string}, + *URL, + *DESCRIPTION, + *FEATURED_IMAGE, + *BODY, + {name: documents, widget: object, fields: [ + *TITLE, + {name: items, widget: list, fields: [ + *TITLE, + {label: Description, name: desc, widget: string}, + {label: File, name: src, widget: file}, + ]}, + ]}, + ] + - &CONTACT_FIELDS [ + *TITLE, + *URL, + {name: subtitle, widget: string}, + *DESCRIPTION, + {name: cards, widget: object, fields: [ + *TITLE, + {name: grzs, widget: object, fields: [ + {name: name, widget: string}, + {name: address, widget: string}, + {name: post, widget: string}, + {name: map, widget: object, fields: [ + {name: text, widget: string}, + {name: url, widget: string}, + ]}, + {label: EMŠO, name: emso, widget: object, fields: [ + {name: text, widget: string}, + {name: value, widget: string}, + ]}, + {name: vat, widget: object, fields: [ + {name: text, widget: string}, + {name: value, widget: string}, + ]}, + {label: Additional info, name: info, widget: string}, + ]}, + {label: Open hours, name: openHours, widget: object, fields: [ + *TITLE, + {name: hours, widget: list, fields: [ + {name: name, widget: string}, + {name: value, widget: string}, + ]}, + ]}, + {name: contact, widget: object, fields: [ + {name: phone, widget: string}, + {name: email, widget: string}, + ]}, + {label: "Additional info", name: "infos", widget: list, fields: [ + {name: name, widget: string}, + {name: value, widget: string}, + ]}, + {label: Cta Contact, name: contactCta, widget: object, fields: [ + {name: phone, widget: string}, + {name: email, widget: string}, + ]}, + ]}, + {name: documents, widget: object, fields: [ + *TITLE, + {name: items, widget: list, fields: [ + {label: Description, name: desc, widget: string}, + ]}, + ]}, + ] + - &MEDIACENTER_FIELDS [ + *TITLE, + *URL, + *DESCRIPTION, + *FEATURED_IMAGE, + {name: person, widget: object, fields: [ + *TITLE, + {name: name, widget: string}, + {name: position, widget: string}, + {name: phone, widget: string}, + {name: email, widget: string}, + ]}, + {name: documents, widget: object, fields: [ + *TITLE, + {name: items, widget: list, fields: [ + *TITLE, + {label: Description, name: desc, widget: string}, + {label: File, name: src, widget: file}, + ]}, + ]}, + ] + - &MENU_ITEM_FIELDS [ + {name: name, widget: string}, + {name: url, widget: string}, + {name: identifier, widget: string, required: false}, + {name: parent, widget: string, required: false}, + {name: weight, widget: number, required: false}, + ] + - &MENU_FIELDS [ + {name: main, widget: list, label_singular: item, fields: *MENU_ITEM_FIELDS}, + {name: upper, widget: list, label_singular: item, fields: *MENU_ITEM_FIELDS}, + {name: donate, widget: list, label_singular: item, fields: *MENU_ITEM_FIELDS}, + ] + - &CONDITIONS_FIELDS [ + *TITLE, + *DRAFT, + *URL, + *DESCRIPTION, + {label: Description Markdown, name: descriptionHTML, widget: markdown, minimal: true}, + *BODY, + ] - - { label: 'Body', name: 'body', widget: 'markdown', hint: 'Main content goes here.' } +collections: + - name: novice + format: yaml-frontmatter + label: Novice + label_singular: article (novice) + folder: content/aktualno/novice + create: true + slug: "{{slug}}" + filter: {field: tags, value: article} + preview_path: aktualno/novice/{{slug}} + i18n: true + editor: + preview: false + fields: [ + *TITLE, + *DRAFT, + *SLUG, + {label: Category, name: categories, widget: select, multiple: true, i18n: duplicate, options: [ + {label: Fotogalerija, value: fotogalerija}, + {label: Novica, value: novica}, + {label: Reševalne akcije, value: resevalne-akcije}, + {label: Dogodki, value: dogodki}, + {label: Video, value: video}, + {label: V spomin, value: v-spomin}, + ]}, + *DATE, + *GRS_UNIT, + *AUTHOR, + *TEASER, + *DESCRIPTION, + *FEATURED_IMAGE, + *BODY, + *GALLERY, + *TAGS, + *LAYOUT, + ] - - name: 'restaurants' # Used in routes, ie.: /admin/collections/:slug/edit - label: 'Restaurants' # Used in the UI - label_singular: 'Restaurant' # Used in the UI, ie: "New Post" - description: > - Restaurants is an entry type used for testing galleries, relations and other widgets. - The tests must be written in such way that adding new fields does not affect previous flows. - folder: '_restaurants' - slug: '{{year}}-{{month}}-{{day}}-{{slug}}' - summary: '{{title}} -- {{year}}/{{month}}/{{day}}' - create: true # Allow users to create new documents in this collection - fields: # The fields each document in this collection have - - { label: 'Title', name: 'title', widget: 'string', tagname: 'h1' } - - { label: 'Body', name: 'body', widget: 'markdown', hint: 'Main content goes here.' } - - { name: 'gallery', widget: 'image', choose_url: true, media_library: {config: {multiple: true, max_files: 999}}} - - { name: 'post', widget: relation, collection: posts, multiple: true, search_fields: [ "title" ], display_fields: [ "title" ], value_field: "{{slug}}", filters: [ {field: "draft", values: [false]} ] } - - name: authors - label: Authors - label_singular: 'Author' - widget: list - fields: - - { label: 'Name', name: 'name', widget: 'string', hint: 'First and Last' } - - { label: 'Description', name: 'description', widget: 'markdown' } + - name: nasveti + format: yaml-frontmatter + label: Nasveti + label_singular: article (nasveti) + folder: content/resevanje/nasveti-grzs + create: true + slug: "{{slug}}" + filter: {field: tags, value: article} + preview_path: resevanje/nasveti/{{slug}} + i18n: true + editor: + preview: false + fields: [ + *TITLE, + *DRAFT, + *URL, + {label: Category, name: tipCategories, widget: select, multiple: true, options: [ + {label: Video, value: video}, + {label: Varno v gore, value: Varno v gore}, + ]}, + *DATE, + *GRS_UNIT, + *AUTHOR, + *TEASER, + *DESCRIPTION, + *FEATURED_IMAGE, + *BODY, + *GALLERY, + *TAGS, + *LAYOUT, + ] - - name: 'faq' # Used in routes, ie.: /admin/collections/:slug/edit - label: 'FAQ' # Used in the UI - folder: '_faqs' - create: true # Allow users to create new documents in this collection - fields: # The fields each document in this collection have - - { label: 'Question', name: 'title', widget: 'string', tagname: 'h1' } - - { label: 'Answer', name: 'body', widget: 'markdown' } + - name: medijsko-sredisce + format: yaml-frontmatter + label: Medijsko središče + label_singular: article (medijsko središče) + folder: "content/medijsko-sredisce" + create: true + slug: "{{slug}}" + filter: {field: tags, value: article} + preview_path: medijsko-sredisce/{{slug}} + i18n: true + editor: + preview: false + fields: [ + *TITLE, + *DRAFT, + *SLUG, + *DATE, + *GRS_UNIT, + *AUTHOR, + *TEASER, + *DESCRIPTION, + *SHOW_FEATURED, + *FEATURED_IMAGE, + *BODY, + *GALLERY, + *TAGS, + *LAYOUT, + ] - - name: 'settings' - label: 'Settings' - delete: false # Prevent users from deleting documents in this collection + - label: Pages + name: pages editor: preview: false - files: - - name: 'general' - label: 'Site Settings' - file: '_data/settings.json' - description: 'General Site Settings' - fields: - - { label: 'Global title', name: 'site_title', widget: 'string' } - - label: 'Post Settings' - name: posts - widget: 'object' - fields: - - { - label: 'Number of posts on frontpage', - name: front_limit, - widget: number, - min: 1, - max: 10, - } - - { label: 'Default Author', name: author, widget: string } - - { - label: 'Default Thumbnail', - name: thumb, - widget: image, - class: 'thumb', - required: false, - } + files: [ + {label: Domov SL, name: home-sl, file: content/_index.sl.md, fields: *HOME_FIELDS}, + {label: Domov EN, name: home-en, file: content/_index.en.md, fields: *HOME_FIELDS}, + {label: Društva in postaje SL, name: drustva-in-postaje-sl, file: content/o-grzs/drustva-in-postaje.sl.md, fields: *PAGE_FIELDS}, + {label: Društva in postaje EN, name: drustva-in-postaje-en, file: content/o-grzs/drustva-in-postaje.en.md, fields: *PAGE_FIELDS}, + {label: IKAR SL, name: ikar-sl, file: content/o-grzs/ikar-mednarodno-resevanje.sl.md, fields: *PAGE_FIELDS}, + {label: IKAR EN, name: ikar-en, file: content/o-grzs/ikar-mednarodno-resevanje.en.md, fields: *PAGE_FIELDS}, + {label: Sklad Okrešelj SL, name: sklad-okreselj-sl, file: content/o-grzs/sklad-okreselj.sl.md, fields: *PAGE_FIELDS}, + {label: Sklad Okrešelj EN, name: sklad-okreselj-en, file: content/o-grzs/sklad-okreselj.en.md, fields: *PAGE_FIELDS}, + {label: Nameni del dohodnine SL, name: dohodnina-sl, file: content/postani-podpornik/nameni-del-dohodnine.sl.md, fields: *PAGE_FIELDS}, + {label: Nameni del dohodnine EN, name: dohodnina-en, file: content/postani-podpornik/nameni-del-dohodnine.en.md, fields: *PAGE_FIELDS}, + {label: Doniraj SL, name: doniraj-sl, file: content/postani-podpornik/doniraj.sl.md, fields: *PAGE_FIELDS}, + {label: Doniraj EN, name: doniraj-en, file: content/postani-podpornik/doniraj.en.md, fields: *PAGE_FIELDS}, + {label: Pravila in pogoji SL, name: pravila-in-pogoji-sl, file: content/pravila-in-pogoji.sl.md, fields: *PAGE_FIELDS}, + {label: Pravila in pogoji EN, name: pravila-in-pogoji-en, file: content/pravila-in-pogoji.en.md, fields: *PAGE_FIELDS}, + {label: Piskotki SL, name: piskotki-sl, file: content/piskotki.sl.md, fields: *PAGE_FIELDS}, + {label: Piskotki EN, name: piskotki-en, file: content/piskotki.en.md, fields: *PAGE_FIELDS}, + {label: Varstvo osebnih podatkov SL, name: varstvo-osebnih-podatkov-sl, file: content/varstvo-osebnih-podatkov.sl.md, fields: *PAGE_FIELDS}, + {label: Varstvo osebnih podatkov EN, name: varstvo-osebnih-podatkov-en, file: content/varstvo-osebnih-podatkov.en.md, fields: *PAGE_FIELDS}, + {label: Kdo je gorski reševalec SL, name: kdo-je-gorski-resevalec-sl, file: content/resevanje/kdo-je-gorski-resevalec.sl.md, fields: *PAGE_FIELDS}, + {label: Kdo je gorski reševalec EN, name: kdo-je-gorski-resevalec-en, file: content/resevanje/kdo-je-gorski-resevalec.en.md, fields: *PAGE_FIELDS}, + {label: Klic v sili SL, name: klic-v-sili-sl, file: content/resevanje/klic-v-sili.sl.md, fields: *PAGE_FIELDS}, + {label: Klic v sili EN, name: klic-v-sili-en, file: content/resevanje/klic-v-sili.en.md, fields: *PAGE_FIELDS}, + {label: Predstavitev GRZS SL, name: predstavitev-sl, file: content/o-grzs/predstavitev.sl.md, fields: *ABOUT_FIELDS}, + {label: Predstavitev GRZS EN, name: predstavitev-en, file: content/o-grzs/predstavitev.en.md, fields: *ABOUT_FIELDS}, + {label: Kontakt GRZS SL, name: kontakt-sl, file: content/o-grzs/kontakt.sl.md, fields: *CONTACT_FIELDS}, + {label: Kontakt GRZS EN, name: kontakt-en, file: content/o-grzs/kontakt.en.md, fields: *CONTACT_FIELDS}, + {label: Media center SL, name: media-center-sl, file: content/medijsko-sredisce/_index.sl.md, fields: *MEDIACENTER_FIELDS}, + {label: Media center EN, name: media-center-en, file: content/medijsko-sredisce/_index.en.md, fields: *MEDIACENTER_FIELDS}, + {label: Aktualne razmere SL, name: conditions-sl, file: content/aktualno/razmere.sl.md, fields: *CONDITIONS_FIELDS}, + {label: Aktualne razmere EN, name: conditions-en, file: content/aktualno/razmere.en.md, fields: *CONDITIONS_FIELDS}, + ] - - name: 'authors' - label: 'Authors' - file: '_data/authors.yml' - description: 'Author descriptions' - fields: - - name: authors - label: Authors - label_singular: 'Author' - widget: list - fields: - - { label: 'Name', name: 'name', widget: 'string', hint: 'First and Last' } - - { label: 'Description', name: 'description', widget: 'markdown' } + - name: components + label: Components + i18n: + structure: single_file + editor: + preview: false + files: [ + {label: Card 112, name: card112, file: data/card112.json, i18n: true, fields: [ + *TITLE, + {label: Call Button, name: callButton, widget: object, i18n: true, fields: [ + {name: text, widget: string, i18n: true}, + {label: Link, name: src, widget: string, i18n: true}, + ]}, + {label: Foreign texts, name: "foreign", widget: object, i18n: true, fields: [ + {label: Austria, name: at, widget: string, i18n: true}, + {label: Italija, name: it, widget: string, i18n: true}, + {label: Hrvaška, name: hr, widget: string, i18n: true}, + {label: Madžarska, name: h, widget: string, i18n: true}, + ]}, + ]}, + {label: Partners, name: partners, file: data/partners.json, i18n: true, fields: [ + {name: supertitle, widget: string, i18n: true}, + *TITLE, + {name: items, widget: list, i18n: true, fields: [ + {name: title, widget: string, i18n: true}, + {name: image, widget: image, i18n: duplicate}, + ]}, + ]}, + {label: Partners Similar, name: partners-similar, file: data/partnersSimilar.json, i18n: true, fields: [ + {name: supertitle, widget: string, i18n: true}, + *TITLE, + {name: items, widget: list, i18n: true, fields: [ + {name: title, widget: string, i18n: true}, + {name: image, widget: image, i18n: duplicate}, + {name: href, widget: string, i18n: duplicate}, + ]}, + ]}, + {label: Newsletter, name: newsletter, file: data/newsletter.json, i18n: true, fields: [ + {name: supertitle, widget: string, i18n: true}, + *TITLE, + {name: success, widget: text, i18n: true}, + {name: email, widget: string, i18n: true}, + {name: submit, widget: string, i18n: true}, + {name: error, widget: string, i18n: true}, + {name: emailError, widget: string, i18n: true}, + {name: terms, widget: text, i18n: true}, + {name: required, widget: string, i18n: true}, + ]}, + {label: Footer, name: footer, file: data/footer.json, i18n: true, fields: [ + {name: copyright, widget: string, i18n: true}, + {name: social, widgets: list, i18n: true, fields: [ + {name: href, widget: string, i18n: true}, + {name: icon, widget: string, i18n: duplicate}, + {name: title, widget: string, i18n: true}, + ]}, + *BUTTON, + {name: legal, widgets: list, i18n: true, fields: [ + {name: href, widget: string, i18n: true}, + {name: title, widget: string, i18n: true}, + ]}, + ]}, + ] - - name: 'kitchenSink' # all the things in one entry, for documentation and quick testing - label: 'Kitchen Sink' - folder: '_sink' - create: true - fields: - - label: 'Related Post' - name: 'post' - widget: 'relationKitchenSinkPost' - collection: 'posts' - display_fields: ['title', 'datetime'] - search_fields: ['title', 'body'] - value_field: 'title' - - { label: 'Title', name: 'title', widget: 'string' } - - { label: 'Boolean', name: 'boolean', widget: 'boolean', default: true } - - { label: 'Map', name: 'map', widget: 'map' } - - { label: 'Text', name: 'text', widget: 'text', hint: 'Plain text, not markdown' } - - { label: 'Number', name: 'number', widget: 'number', hint: 'To infinity and beyond!' } - - { label: 'Markdown', name: 'markdown', widget: 'markdown' } - - { label: 'Datetime', name: 'datetime', widget: 'datetime' } - - { label: 'Image', name: 'image', widget: 'image' } - - { label: 'File', name: 'file', widget: 'file' } - - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } - - { - label: 'Select multiple', - name: 'select_multiple', - widget: 'select', - options: ['a', 'b', 'c'], - multiple: true, - } - - { label: 'Hidden', name: 'hidden', widget: 'hidden', default: 'hidden' } - - { label: 'Color', name: 'color', widget: 'color' } - - label: 'Object' - name: 'object' - widget: 'object' - collapsed: true - fields: - - label: 'Related Post' - name: 'post' - widget: 'relationKitchenSinkPost' - collection: 'posts' - search_fields: ['title', 'body'] - value_field: 'title' - - { label: 'String', name: 'string', widget: 'string' } - - { label: 'Boolean', name: 'boolean', widget: 'boolean', default: false } - - { label: 'Text', name: 'text', widget: 'text' } - - { label: 'Number', name: 'number', widget: 'number' } - - { label: 'Markdown', name: 'markdown', widget: 'markdown' } - - { label: 'Datetime', name: 'datetime', widget: 'datetime' } - - { label: 'Image', name: 'image', widget: 'image' } - - { label: 'File', name: 'file', widget: 'file' } - - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } - - label: 'List' - name: 'list' - widget: 'list' - fields: - - { label: 'String', name: 'string', widget: 'string' } - - { label: 'Boolean', name: 'boolean', widget: 'boolean' } - - { label: 'Text', name: 'text', widget: 'text' } - - { label: 'Number', name: 'number', widget: 'number' } - - { label: 'Markdown', name: 'markdown', widget: 'markdown' } - - { label: 'Datetime', name: 'datetime', widget: 'datetime' } - - { label: 'Image', name: 'image', widget: 'image' } - - { label: 'File', name: 'file', widget: 'file' } - - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } - - label: 'Object' - name: 'object' - widget: 'object' - fields: - - { label: 'String', name: 'string', widget: 'string' } - - { label: 'Boolean', name: 'boolean', widget: 'boolean' } - - { label: 'Text', name: 'text', widget: 'text' } - - { label: 'Number', name: 'number', widget: 'number' } - - { label: 'Markdown', name: 'markdown', widget: 'markdown' } - - { label: 'Datetime', name: 'datetime', widget: 'datetime' } - - { label: 'Image', name: 'image', widget: 'image' } - - { label: 'File', name: 'file', widget: 'file' } - - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } - - label: 'List' - name: 'list' - widget: 'list' - fields: - - label: 'Related Post' - name: 'post' - widget: 'relationKitchenSinkPost' - collection: 'posts' - search_fields: ['title', 'body'] - value_field: 'title' - - { label: 'String', name: 'string', widget: 'string' } - - { label: 'Boolean', name: 'boolean', widget: 'boolean' } - - { label: 'Text', name: 'text', widget: 'text' } - - { label: 'Number', name: 'number', widget: 'number' } - - { label: 'Markdown', name: 'markdown', widget: 'markdown' } - - { label: 'Datetime', name: 'datetime', widget: 'datetime' } - - { label: 'Image', name: 'image', widget: 'image' } - - { label: 'File', name: 'file', widget: 'file' } - - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } - - { label: 'Hidden', name: 'hidden', widget: 'hidden', default: 'hidden' } - - label: 'Object' - name: 'object' - widget: 'object' - fields: - - { label: 'String', name: 'string', widget: 'string' } - - { label: 'Boolean', name: 'boolean', widget: 'boolean' } - - { label: 'Text', name: 'text', widget: 'text' } - - { label: 'Number', name: 'number', widget: 'number' } - - { label: 'Markdown', name: 'markdown', widget: 'markdown' } - - { label: 'Datetime', name: 'datetime', widget: 'datetime' } - - { label: 'Image', name: 'image', widget: 'image' } - - { label: 'File', name: 'file', widget: 'file' } - - { - label: 'Select', - name: 'select', - widget: 'select', - options: ['a', 'b', 'c'], - } - - label: 'Typed List' - name: 'typed_list' - widget: 'list' - types: - - label: 'Type 1 Object' - name: 'type_1_object' - widget: 'object' - fields: - - { label: 'String', name: 'string', widget: 'string' } - - { label: 'Boolean', name: 'boolean', widget: 'boolean' } - - { label: 'Text', name: 'text', widget: 'text' } - - label: 'Type 2 Object' - name: 'type_2_object' - widget: 'object' - fields: - - { label: 'Number', name: 'number', widget: 'number' } - - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } - - { label: 'Datetime', name: 'datetime', widget: 'datetime' } - - { label: 'Markdown', name: 'markdown', widget: 'markdown' } - - label: 'Type 3 Object' - name: 'type_3_object' - widget: 'object' - fields: - - { label: 'Image', name: 'image', widget: 'image' } - - { label: 'File', name: 'file', widget: 'file' } - - name: pages # a nested collection - label: Pages - label_singular: 'Page' - folder: _pages - create: true - nested: { depth: 100 } - fields: - - label: Title - name: title - widget: string - meta: { path: { widget: string, label: 'Path', index_file: 'index' } } + - name: general + label: General + editor: + preview: false + files: [ + {label: Menus SL, name: menus-sl, file: config/_default/menus.sl.json, fields: *MENU_FIELDS}, + {label: Menus EN, name: menus-en, file: config/_default/menus.en.json, fields: *MENU_FIELDS}, + ] diff --git a/packages/decap-cms-core/src/backend.ts b/packages/decap-cms-core/src/backend.ts index f2c1a274c6e5..f42ce728bcbb 100644 --- a/packages/decap-cms-core/src/backend.ts +++ b/packages/decap-cms-core/src/backend.ts @@ -514,7 +514,19 @@ export class Backend { }, ), ); - const formattedEntries = entries.map(this.entryWithFormat(collection)); + + const errors: string[] = []; + // const formattedEntries = entries.map(this.entryWithFormat(collection)); + const formattedEntries = entries.map(entry => { + try { + return this.entryWithFormat(collection)(entry); + } catch (error) { + console.error(`Error processing entry at ${entry.path}`, error); + errors.push(entry.path); + return null; + } + }).filter(e => e !== null); + // todo: find error somewhere here and put it to errors array // If this collection has a "filter" property, filter entries accordingly const collectionFilter = collection.get('filter'); @@ -525,10 +537,10 @@ export class Backend { if (hasI18n(collection)) { const extension = selectFolderEntryExtension(collection); const groupedEntries = groupEntries(collection, extension, filteredEntries); - return groupedEntries; + return {entries: groupedEntries, errors}; } // todo: return object { entries, errors } + change all other processEntries uses to just take entries - return filteredEntries; + return {entries: filteredEntries, errors}; } async listEntries(collection: Collection) { @@ -569,13 +581,13 @@ export class Backend { collection, }); + const { entries, errors } = this.processEntries(loadedEntries, collection); + return { - entries: this.processEntries(loadedEntries, collection), + entries, pagination: cursor.meta?.get('page'), cursor, - errors: [ - 'error found in process entries' - ] + errors, }; } @@ -647,7 +659,7 @@ export class Backend { ]; } const filteredSearchFields = searchFields.filter(Boolean) as string[]; - const collectionEntries = await this.listAllEntries(collection); + const collectionEntries = (await this.listAllEntries(collection)).entries; return fuzzy.filter(searchTerm, collectionEntries, { extract: extractSearchFields(uniq(filteredSearchFields)), }); @@ -681,7 +693,7 @@ export class Backend { file?: string, limit?: number, ) { - let entries = await this.listAllEntries(collection); + let { entries } = await this.listAllEntries(collection); if (file) { entries = entries.filter(e => e.slug === file); } @@ -711,7 +723,7 @@ export class Backend { const collection = data.get('collection') as Collection; return this.implementation!.traverseCursor!(unwrappedCursor, action).then( async ({ entries, cursor: newCursor }) => ({ - entries: this.processEntries(entries, collection), + entries: this.processEntries(entries, collection).entries, cursor: Cursor.create(newCursor).wrapData({ cursorType: 'collectionEntries', collection, From 547f5d769781fcdb190f3b24d890f1cd8e1125c9 Mon Sep 17 00:00:00 2001 From: Martin Jagodic Date: Wed, 4 Sep 2024 15:03:55 +0200 Subject: [PATCH 04/10] fix: revert config --- dev-test/config.yml | 680 +++++++++++++++++--------------------------- 1 file changed, 268 insertions(+), 412 deletions(-) diff --git a/dev-test/config.yml b/dev-test/config.yml index 46e4142ce1f0..d9bf6182a7cc 100644 --- a/dev-test/config.yml +++ b/dev-test/config.yml @@ -1,424 +1,280 @@ -local_backend: true - backend: - name: git-gateway - branch: __BRANCH__ - squash_merges: true + name: test-repo -display_url: https://www.grzs.si -logo_url: /media/brand/logo.png -media_folder: static/media/uploads -public_folder: /media/uploads +site_url: https://example.com -slug: - encoding: ascii - clean_accents: true -i18n: - structure: multiple_files - locales: [sl, en] +publish_mode: editorial_workflow +media_folder: assets/uploads -aliases: - - &TITLE {name: title, label: Title, widget: string, i18n: true} - - &DRAFT {name: draft, label: Draft, widget: boolean, required: false, i18n: true} - - &SLUG {name: slug, label: Slug, widget: string, required: false, i18n: true} - - &URL {name: url, label: URL, widget: string, required: false, i18n: true} - - &DESCRIPTION {label: Description, name: description, widget: text, i18n: true} - - &BODY {label: Content, name: body, widget: markdown, i18n: true} - - &DATE {label: Date, name: date, widget: datetime, i18n: duplicate} - - &GRS_UNIT {label: GRS Unit, name: unit, widget: string, required: false, i18n: duplicate} - - &AUTHOR {label: Author, name: author, widget: string, required: false, i18n: true} - - &TEASER {label: Teaser, name: teaser, widget: string, i18n: true} - - &TAGS {name: tags, widget: hidden, default: [article], i18n: duplicate} - - &LAYOUT {name: layout, widget: hidden, default: article, i18n: duplicate} - - &SHOW_FEATURED {label: Show featured image on page, name: showFeatured, i18n: duplicate, widget: select, options: ['false', 'true']} - - &FEATURED_IMAGE {label: Featured image, name: image, required: false, i18n: true, widget: object, fields: [ - {label: Source, name: src, widget: image, required: false, i18n: duplicate}, - {label: Text, name: alt, widget: string, required: false, i18n: true}, - ]} - - &BUTTON {name: button, i18n: true, widget: object, fields: [ - {name: href, widget: string, i18n: true}, - {name: text, widget: string, i18n: true}, - ]} - - &GALLERY {name: gallery, widget: list, required: false, i18n: true, fields: [ - {label: Image, name: src, widget: image, i18n: duplicate}, - {name: text, widget: string, required: false, i18n: true} - ]} - - &PAGE_FIELDS [ - *TITLE, - *URL, - *SHOW_FEATURED, - *FEATURED_IMAGE, - *BODY, - *GALLERY, - ] - - &HOME_FIELDS [ - *TITLE, - *DESCRIPTION, - {label: Gallery 1, name: "swipeGalleryTop", widget: list, fields: [ - {label: Image, name: src, widget: image}, - {name: text, widget: string}, - ]}, - {label: Gallery 2, name: swipeGalleryMiddle, widget: list, fields: [ - {label: Image, name: src, widget: image}, - {name: text, widget: string}, - ]}, - {label: Gallery 3, name: swipeGalleryBottom, widget: list, fields: [ - {label: Image, name: src, widget: image}, - {name: text, widget: string} - ]}, - {name: help, widget: object, fields: [ - {name: supertitle, widget: string}, - {name: title, widget: string}, - {name: text, widget: text}, - {name: topics, widget: list, fields: [ - {name: title, widget: string}, - ]}, - *BUTTON, - ]}, - {name: support, widget: object, fields: [ - {name: supertitle, widget: string}, - {name: title, widget: string}, - {name: text, widget: text}, - ]}, - {name: responsibility, widget: object, fields: [ - {name: title, widget: string}, - {name: links, widget: list, fields: [ - {name: title, widget: text}, - {name: desc, widget: text}, - {name: href, widget: string}, - ]}, - ]}, - {name: banner, widget: object, fields: [ - {name: href, widget: string, required: false}, - {name: title, widget: string, required: false}, - {name: srcMobile, label: mobile image, widget: image, required: false}, - {name: srcDesktop, label: destop image, widget: image, required: false}, - ]}, - {name: news, widget: object, fields: [ - {name: supertitle, widget: string, required: false}, - {name: title, widget: string}, - *BUTTON, - ]}, - {label: Slider, name: exposedContent, allow_add: true, widget: list, required: true, fields: [ - *TITLE, - {label: Description, name: desc, widget: string}, - {label: Link for button more, name: href, widget: string}, - {label: Order, name: weight, widget: number}, - ]} - ] - - &ABOUT_FIELDS [ - {name: foreword, widget: string}, - {label: Title, name: titleText, widget: string}, - *URL, - *DESCRIPTION, - *FEATURED_IMAGE, - *BODY, - {name: documents, widget: object, fields: [ - *TITLE, - {name: items, widget: list, fields: [ - *TITLE, - {label: Description, name: desc, widget: string}, - {label: File, name: src, widget: file}, - ]}, - ]}, - ] - - &CONTACT_FIELDS [ - *TITLE, - *URL, - {name: subtitle, widget: string}, - *DESCRIPTION, - {name: cards, widget: object, fields: [ - *TITLE, - {name: grzs, widget: object, fields: [ - {name: name, widget: string}, - {name: address, widget: string}, - {name: post, widget: string}, - {name: map, widget: object, fields: [ - {name: text, widget: string}, - {name: url, widget: string}, - ]}, - {label: EMŠO, name: emso, widget: object, fields: [ - {name: text, widget: string}, - {name: value, widget: string}, - ]}, - {name: vat, widget: object, fields: [ - {name: text, widget: string}, - {name: value, widget: string}, - ]}, - {label: Additional info, name: info, widget: string}, - ]}, - {label: Open hours, name: openHours, widget: object, fields: [ - *TITLE, - {name: hours, widget: list, fields: [ - {name: name, widget: string}, - {name: value, widget: string}, - ]}, - ]}, - {name: contact, widget: object, fields: [ - {name: phone, widget: string}, - {name: email, widget: string}, - ]}, - {label: "Additional info", name: "infos", widget: list, fields: [ - {name: name, widget: string}, - {name: value, widget: string}, - ]}, - {label: Cta Contact, name: contactCta, widget: object, fields: [ - {name: phone, widget: string}, - {name: email, widget: string}, - ]}, - ]}, - {name: documents, widget: object, fields: [ - *TITLE, - {name: items, widget: list, fields: [ - {label: Description, name: desc, widget: string}, - ]}, - ]}, - ] - - &MEDIACENTER_FIELDS [ - *TITLE, - *URL, - *DESCRIPTION, - *FEATURED_IMAGE, - {name: person, widget: object, fields: [ - *TITLE, - {name: name, widget: string}, - {name: position, widget: string}, - {name: phone, widget: string}, - {name: email, widget: string}, - ]}, - {name: documents, widget: object, fields: [ - *TITLE, - {name: items, widget: list, fields: [ - *TITLE, - {label: Description, name: desc, widget: string}, - {label: File, name: src, widget: file}, - ]}, - ]}, - ] - - &MENU_ITEM_FIELDS [ - {name: name, widget: string}, - {name: url, widget: string}, - {name: identifier, widget: string, required: false}, - {name: parent, widget: string, required: false}, - {name: weight, widget: number, required: false}, - ] - - &MENU_FIELDS [ - {name: main, widget: list, label_singular: item, fields: *MENU_ITEM_FIELDS}, - {name: upper, widget: list, label_singular: item, fields: *MENU_ITEM_FIELDS}, - {name: donate, widget: list, label_singular: item, fields: *MENU_ITEM_FIELDS}, - ] - - &CONDITIONS_FIELDS [ - *TITLE, - *DRAFT, - *URL, - *DESCRIPTION, - {label: Description Markdown, name: descriptionHTML, widget: markdown, minimal: true}, - *BODY, - ] +collections: # A list of collections the CMS should be able to edit + - name: 'posts' # Used in routes, ie.: /admin/collections/:slug/edit + label: 'Posts' # Used in the UI + label_singular: 'Post' # Used in the UI, ie: "New Post" + description: > + The description is a great place for tone setting, high level information, and editing + guidelines that are specific to a collection. + folder: '_posts' + slug: '{{year}}-{{month}}-{{day}}-{{slug}}' + summary: '{{title}} -- {{year}}/{{month}}/{{day}}' + create: true # Allow users to create new documents in this collection + view_filters: + - label: Posts With Index + field: title + pattern: 'This is post #' + - label: Posts Without Index + field: title + pattern: front matter post + - label: Drafts + field: draft + pattern: true + view_groups: + - label: Year + field: date + pattern: \d{4} + - label: Drafts + field: draft + fields: # The fields each document in this collection have + - { label: 'Title', name: 'title', widget: 'string', tagname: 'h1' } + - { label: 'Draft', name: 'draft', widget: 'boolean', default: false } + - { + label: 'Publish Date', + name: 'date', + widget: 'datetime', + format: 'YYYY-MM-DD HH:mm', + default: '{{now}}', + } + - label: 'Cover Image' + name: 'image' + widget: 'image' + required: false + tagname: '' -collections: - - name: novice - format: yaml-frontmatter - label: Novice - label_singular: article (novice) - folder: content/aktualno/novice - create: true - slug: "{{slug}}" - filter: {field: tags, value: article} - preview_path: aktualno/novice/{{slug}} - i18n: true - editor: - preview: false - fields: [ - *TITLE, - *DRAFT, - *SLUG, - {label: Category, name: categories, widget: select, multiple: true, i18n: duplicate, options: [ - {label: Fotogalerija, value: fotogalerija}, - {label: Novica, value: novica}, - {label: Reševalne akcije, value: resevalne-akcije}, - {label: Dogodki, value: dogodki}, - {label: Video, value: video}, - {label: V spomin, value: v-spomin}, - ]}, - *DATE, - *GRS_UNIT, - *AUTHOR, - *TEASER, - *DESCRIPTION, - *FEATURED_IMAGE, - *BODY, - *GALLERY, - *TAGS, - *LAYOUT, - ] + - { label: 'Body', name: 'body', widget: 'markdown', hint: 'Main content goes here.' } - - name: nasveti - format: yaml-frontmatter - label: Nasveti - label_singular: article (nasveti) - folder: content/resevanje/nasveti-grzs - create: true - slug: "{{slug}}" - filter: {field: tags, value: article} - preview_path: resevanje/nasveti/{{slug}} - i18n: true - editor: - preview: false - fields: [ - *TITLE, - *DRAFT, - *URL, - {label: Category, name: tipCategories, widget: select, multiple: true, options: [ - {label: Video, value: video}, - {label: Varno v gore, value: Varno v gore}, - ]}, - *DATE, - *GRS_UNIT, - *AUTHOR, - *TEASER, - *DESCRIPTION, - *FEATURED_IMAGE, - *BODY, - *GALLERY, - *TAGS, - *LAYOUT, - ] + - name: 'restaurants' # Used in routes, ie.: /admin/collections/:slug/edit + label: 'Restaurants' # Used in the UI + label_singular: 'Restaurant' # Used in the UI, ie: "New Post" + description: > + Restaurants is an entry type used for testing galleries, relations and other widgets. + The tests must be written in such way that adding new fields does not affect previous flows. + folder: '_restaurants' + slug: '{{year}}-{{month}}-{{day}}-{{slug}}' + summary: '{{title}} -- {{year}}/{{month}}/{{day}}' + create: true # Allow users to create new documents in this collection + fields: # The fields each document in this collection have + - { label: 'Title', name: 'title', widget: 'string', tagname: 'h1' } + - { label: 'Body', name: 'body', widget: 'markdown', hint: 'Main content goes here.' } + - { name: 'gallery', widget: 'image', choose_url: true, media_library: {config: {multiple: true, max_files: 999}}} + - { name: 'post', widget: relation, collection: posts, multiple: true, search_fields: [ "title" ], display_fields: [ "title" ], value_field: "{{slug}}", filters: [ {field: "draft", values: [false]} ] } + - name: authors + label: Authors + label_singular: 'Author' + widget: list + fields: + - { label: 'Name', name: 'name', widget: 'string', hint: 'First and Last' } + - { label: 'Description', name: 'description', widget: 'markdown' } - - name: medijsko-sredisce - format: yaml-frontmatter - label: Medijsko središče - label_singular: article (medijsko središče) - folder: "content/medijsko-sredisce" - create: true - slug: "{{slug}}" - filter: {field: tags, value: article} - preview_path: medijsko-sredisce/{{slug}} - i18n: true - editor: - preview: false - fields: [ - *TITLE, - *DRAFT, - *SLUG, - *DATE, - *GRS_UNIT, - *AUTHOR, - *TEASER, - *DESCRIPTION, - *SHOW_FEATURED, - *FEATURED_IMAGE, - *BODY, - *GALLERY, - *TAGS, - *LAYOUT, - ] + - name: 'faq' # Used in routes, ie.: /admin/collections/:slug/edit + label: 'FAQ' # Used in the UI + folder: '_faqs' + create: true # Allow users to create new documents in this collection + fields: # The fields each document in this collection have + - { label: 'Question', name: 'title', widget: 'string', tagname: 'h1' } + - { label: 'Answer', name: 'body', widget: 'markdown' } - - label: Pages - name: pages + - name: 'settings' + label: 'Settings' + delete: false # Prevent users from deleting documents in this collection editor: preview: false - files: [ - {label: Domov SL, name: home-sl, file: content/_index.sl.md, fields: *HOME_FIELDS}, - {label: Domov EN, name: home-en, file: content/_index.en.md, fields: *HOME_FIELDS}, - {label: Društva in postaje SL, name: drustva-in-postaje-sl, file: content/o-grzs/drustva-in-postaje.sl.md, fields: *PAGE_FIELDS}, - {label: Društva in postaje EN, name: drustva-in-postaje-en, file: content/o-grzs/drustva-in-postaje.en.md, fields: *PAGE_FIELDS}, - {label: IKAR SL, name: ikar-sl, file: content/o-grzs/ikar-mednarodno-resevanje.sl.md, fields: *PAGE_FIELDS}, - {label: IKAR EN, name: ikar-en, file: content/o-grzs/ikar-mednarodno-resevanje.en.md, fields: *PAGE_FIELDS}, - {label: Sklad Okrešelj SL, name: sklad-okreselj-sl, file: content/o-grzs/sklad-okreselj.sl.md, fields: *PAGE_FIELDS}, - {label: Sklad Okrešelj EN, name: sklad-okreselj-en, file: content/o-grzs/sklad-okreselj.en.md, fields: *PAGE_FIELDS}, - {label: Nameni del dohodnine SL, name: dohodnina-sl, file: content/postani-podpornik/nameni-del-dohodnine.sl.md, fields: *PAGE_FIELDS}, - {label: Nameni del dohodnine EN, name: dohodnina-en, file: content/postani-podpornik/nameni-del-dohodnine.en.md, fields: *PAGE_FIELDS}, - {label: Doniraj SL, name: doniraj-sl, file: content/postani-podpornik/doniraj.sl.md, fields: *PAGE_FIELDS}, - {label: Doniraj EN, name: doniraj-en, file: content/postani-podpornik/doniraj.en.md, fields: *PAGE_FIELDS}, - {label: Pravila in pogoji SL, name: pravila-in-pogoji-sl, file: content/pravila-in-pogoji.sl.md, fields: *PAGE_FIELDS}, - {label: Pravila in pogoji EN, name: pravila-in-pogoji-en, file: content/pravila-in-pogoji.en.md, fields: *PAGE_FIELDS}, - {label: Piskotki SL, name: piskotki-sl, file: content/piskotki.sl.md, fields: *PAGE_FIELDS}, - {label: Piskotki EN, name: piskotki-en, file: content/piskotki.en.md, fields: *PAGE_FIELDS}, - {label: Varstvo osebnih podatkov SL, name: varstvo-osebnih-podatkov-sl, file: content/varstvo-osebnih-podatkov.sl.md, fields: *PAGE_FIELDS}, - {label: Varstvo osebnih podatkov EN, name: varstvo-osebnih-podatkov-en, file: content/varstvo-osebnih-podatkov.en.md, fields: *PAGE_FIELDS}, - {label: Kdo je gorski reševalec SL, name: kdo-je-gorski-resevalec-sl, file: content/resevanje/kdo-je-gorski-resevalec.sl.md, fields: *PAGE_FIELDS}, - {label: Kdo je gorski reševalec EN, name: kdo-je-gorski-resevalec-en, file: content/resevanje/kdo-je-gorski-resevalec.en.md, fields: *PAGE_FIELDS}, - {label: Klic v sili SL, name: klic-v-sili-sl, file: content/resevanje/klic-v-sili.sl.md, fields: *PAGE_FIELDS}, - {label: Klic v sili EN, name: klic-v-sili-en, file: content/resevanje/klic-v-sili.en.md, fields: *PAGE_FIELDS}, - {label: Predstavitev GRZS SL, name: predstavitev-sl, file: content/o-grzs/predstavitev.sl.md, fields: *ABOUT_FIELDS}, - {label: Predstavitev GRZS EN, name: predstavitev-en, file: content/o-grzs/predstavitev.en.md, fields: *ABOUT_FIELDS}, - {label: Kontakt GRZS SL, name: kontakt-sl, file: content/o-grzs/kontakt.sl.md, fields: *CONTACT_FIELDS}, - {label: Kontakt GRZS EN, name: kontakt-en, file: content/o-grzs/kontakt.en.md, fields: *CONTACT_FIELDS}, - {label: Media center SL, name: media-center-sl, file: content/medijsko-sredisce/_index.sl.md, fields: *MEDIACENTER_FIELDS}, - {label: Media center EN, name: media-center-en, file: content/medijsko-sredisce/_index.en.md, fields: *MEDIACENTER_FIELDS}, - {label: Aktualne razmere SL, name: conditions-sl, file: content/aktualno/razmere.sl.md, fields: *CONDITIONS_FIELDS}, - {label: Aktualne razmere EN, name: conditions-en, file: content/aktualno/razmere.en.md, fields: *CONDITIONS_FIELDS}, - ] + files: + - name: 'general' + label: 'Site Settings' + file: '_data/settings.json' + description: 'General Site Settings' + fields: + - { label: 'Global title', name: 'site_title', widget: 'string' } + - label: 'Post Settings' + name: posts + widget: 'object' + fields: + - { + label: 'Number of posts on frontpage', + name: front_limit, + widget: number, + min: 1, + max: 10, + } + - { label: 'Default Author', name: author, widget: string } + - { + label: 'Default Thumbnail', + name: thumb, + widget: image, + class: 'thumb', + required: false, + } - - name: components - label: Components - i18n: - structure: single_file - editor: - preview: false - files: [ - {label: Card 112, name: card112, file: data/card112.json, i18n: true, fields: [ - *TITLE, - {label: Call Button, name: callButton, widget: object, i18n: true, fields: [ - {name: text, widget: string, i18n: true}, - {label: Link, name: src, widget: string, i18n: true}, - ]}, - {label: Foreign texts, name: "foreign", widget: object, i18n: true, fields: [ - {label: Austria, name: at, widget: string, i18n: true}, - {label: Italija, name: it, widget: string, i18n: true}, - {label: Hrvaška, name: hr, widget: string, i18n: true}, - {label: Madžarska, name: h, widget: string, i18n: true}, - ]}, - ]}, - {label: Partners, name: partners, file: data/partners.json, i18n: true, fields: [ - {name: supertitle, widget: string, i18n: true}, - *TITLE, - {name: items, widget: list, i18n: true, fields: [ - {name: title, widget: string, i18n: true}, - {name: image, widget: image, i18n: duplicate}, - ]}, - ]}, - {label: Partners Similar, name: partners-similar, file: data/partnersSimilar.json, i18n: true, fields: [ - {name: supertitle, widget: string, i18n: true}, - *TITLE, - {name: items, widget: list, i18n: true, fields: [ - {name: title, widget: string, i18n: true}, - {name: image, widget: image, i18n: duplicate}, - {name: href, widget: string, i18n: duplicate}, - ]}, - ]}, - {label: Newsletter, name: newsletter, file: data/newsletter.json, i18n: true, fields: [ - {name: supertitle, widget: string, i18n: true}, - *TITLE, - {name: success, widget: text, i18n: true}, - {name: email, widget: string, i18n: true}, - {name: submit, widget: string, i18n: true}, - {name: error, widget: string, i18n: true}, - {name: emailError, widget: string, i18n: true}, - {name: terms, widget: text, i18n: true}, - {name: required, widget: string, i18n: true}, - ]}, - {label: Footer, name: footer, file: data/footer.json, i18n: true, fields: [ - {name: copyright, widget: string, i18n: true}, - {name: social, widgets: list, i18n: true, fields: [ - {name: href, widget: string, i18n: true}, - {name: icon, widget: string, i18n: duplicate}, - {name: title, widget: string, i18n: true}, - ]}, - *BUTTON, - {name: legal, widgets: list, i18n: true, fields: [ - {name: href, widget: string, i18n: true}, - {name: title, widget: string, i18n: true}, - ]}, - ]}, - ] + - name: 'authors' + label: 'Authors' + file: '_data/authors.yml' + description: 'Author descriptions' + fields: + - name: authors + label: Authors + label_singular: 'Author' + widget: list + fields: + - { label: 'Name', name: 'name', widget: 'string', hint: 'First and Last' } + - { label: 'Description', name: 'description', widget: 'markdown' } - - name: general - label: General - editor: - preview: false - files: [ - {label: Menus SL, name: menus-sl, file: config/_default/menus.sl.json, fields: *MENU_FIELDS}, - {label: Menus EN, name: menus-en, file: config/_default/menus.en.json, fields: *MENU_FIELDS}, - ] + - name: 'kitchenSink' # all the things in one entry, for documentation and quick testing + label: 'Kitchen Sink' + folder: '_sink' + create: true + fields: + - label: 'Related Post' + name: 'post' + widget: 'relationKitchenSinkPost' + collection: 'posts' + display_fields: ['title', 'datetime'] + search_fields: ['title', 'body'] + value_field: 'title' + - { label: 'Title', name: 'title', widget: 'string' } + - { label: 'Boolean', name: 'boolean', widget: 'boolean', default: true } + - { label: 'Map', name: 'map', widget: 'map' } + - { label: 'Text', name: 'text', widget: 'text', hint: 'Plain text, not markdown' } + - { label: 'Number', name: 'number', widget: 'number', hint: 'To infinity and beyond!' } + - { label: 'Markdown', name: 'markdown', widget: 'markdown' } + - { label: 'Datetime', name: 'datetime', widget: 'datetime' } + - { label: 'Image', name: 'image', widget: 'image' } + - { label: 'File', name: 'file', widget: 'file' } + - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } + - { + label: 'Select multiple', + name: 'select_multiple', + widget: 'select', + options: ['a', 'b', 'c'], + multiple: true, + } + - { label: 'Hidden', name: 'hidden', widget: 'hidden', default: 'hidden' } + - { label: 'Color', name: 'color', widget: 'color' } + - label: 'Object' + name: 'object' + widget: 'object' + collapsed: true + fields: + - label: 'Related Post' + name: 'post' + widget: 'relationKitchenSinkPost' + collection: 'posts' + search_fields: ['title', 'body'] + value_field: 'title' + - { label: 'String', name: 'string', widget: 'string' } + - { label: 'Boolean', name: 'boolean', widget: 'boolean', default: false } + - { label: 'Text', name: 'text', widget: 'text' } + - { label: 'Number', name: 'number', widget: 'number' } + - { label: 'Markdown', name: 'markdown', widget: 'markdown' } + - { label: 'Datetime', name: 'datetime', widget: 'datetime' } + - { label: 'Image', name: 'image', widget: 'image' } + - { label: 'File', name: 'file', widget: 'file' } + - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } + - label: 'List' + name: 'list' + widget: 'list' + fields: + - { label: 'String', name: 'string', widget: 'string' } + - { label: 'Boolean', name: 'boolean', widget: 'boolean' } + - { label: 'Text', name: 'text', widget: 'text' } + - { label: 'Number', name: 'number', widget: 'number' } + - { label: 'Markdown', name: 'markdown', widget: 'markdown' } + - { label: 'Datetime', name: 'datetime', widget: 'datetime' } + - { label: 'Image', name: 'image', widget: 'image' } + - { label: 'File', name: 'file', widget: 'file' } + - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } + - label: 'Object' + name: 'object' + widget: 'object' + fields: + - { label: 'String', name: 'string', widget: 'string' } + - { label: 'Boolean', name: 'boolean', widget: 'boolean' } + - { label: 'Text', name: 'text', widget: 'text' } + - { label: 'Number', name: 'number', widget: 'number' } + - { label: 'Markdown', name: 'markdown', widget: 'markdown' } + - { label: 'Datetime', name: 'datetime', widget: 'datetime' } + - { label: 'Image', name: 'image', widget: 'image' } + - { label: 'File', name: 'file', widget: 'file' } + - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } + - label: 'List' + name: 'list' + widget: 'list' + fields: + - label: 'Related Post' + name: 'post' + widget: 'relationKitchenSinkPost' + collection: 'posts' + search_fields: ['title', 'body'] + value_field: 'title' + - { label: 'String', name: 'string', widget: 'string' } + - { label: 'Boolean', name: 'boolean', widget: 'boolean' } + - { label: 'Text', name: 'text', widget: 'text' } + - { label: 'Number', name: 'number', widget: 'number' } + - { label: 'Markdown', name: 'markdown', widget: 'markdown' } + - { label: 'Datetime', name: 'datetime', widget: 'datetime' } + - { label: 'Image', name: 'image', widget: 'image' } + - { label: 'File', name: 'file', widget: 'file' } + - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } + - { label: 'Hidden', name: 'hidden', widget: 'hidden', default: 'hidden' } + - label: 'Object' + name: 'object' + widget: 'object' + fields: + - { label: 'String', name: 'string', widget: 'string' } + - { label: 'Boolean', name: 'boolean', widget: 'boolean' } + - { label: 'Text', name: 'text', widget: 'text' } + - { label: 'Number', name: 'number', widget: 'number' } + - { label: 'Markdown', name: 'markdown', widget: 'markdown' } + - { label: 'Datetime', name: 'datetime', widget: 'datetime' } + - { label: 'Image', name: 'image', widget: 'image' } + - { label: 'File', name: 'file', widget: 'file' } + - { + label: 'Select', + name: 'select', + widget: 'select', + options: ['a', 'b', 'c'], + } + - label: 'Typed List' + name: 'typed_list' + widget: 'list' + types: + - label: 'Type 1 Object' + name: 'type_1_object' + widget: 'object' + fields: + - { label: 'String', name: 'string', widget: 'string' } + - { label: 'Boolean', name: 'boolean', widget: 'boolean' } + - { label: 'Text', name: 'text', widget: 'text' } + - label: 'Type 2 Object' + name: 'type_2_object' + widget: 'object' + fields: + - { label: 'Number', name: 'number', widget: 'number' } + - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } + - { label: 'Datetime', name: 'datetime', widget: 'datetime' } + - { label: 'Markdown', name: 'markdown', widget: 'markdown' } + - label: 'Type 3 Object' + name: 'type_3_object' + widget: 'object' + fields: + - { label: 'Image', name: 'image', widget: 'image' } + - { label: 'File', name: 'file', widget: 'file' } + - name: pages # a nested collection + label: Pages + label_singular: 'Page' + folder: _pages + create: true + nested: { depth: 100 } + fields: + - label: Title + name: title + widget: string + meta: { path: { widget: string, label: 'Path', index_file: 'index' } } From 8c1b78931e6f060ea4bc2b66cb72537c418f8962 Mon Sep 17 00:00:00 2001 From: Martin Jagodic Date: Wed, 4 Sep 2024 15:15:13 +0200 Subject: [PATCH 05/10] refactor: cleanup --- packages/decap-cms-core/src/backend.ts | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/packages/decap-cms-core/src/backend.ts b/packages/decap-cms-core/src/backend.ts index f42ce728bcbb..c6dd832e64b9 100644 --- a/packages/decap-cms-core/src/backend.ts +++ b/packages/decap-cms-core/src/backend.ts @@ -515,19 +515,10 @@ export class Backend { ), ); - const errors: string[] = []; - // const formattedEntries = entries.map(this.entryWithFormat(collection)); - const formattedEntries = entries.map(entry => { - try { - return this.entryWithFormat(collection)(entry); - } catch (error) { - console.error(`Error processing entry at ${entry.path}`, error); - errors.push(entry.path); - return null; - } - }).filter(e => e !== null); + const formattedEntries = entries.map(this.entryWithFormat(collection)); + const errors = formattedEntries.filter(e => e.parseError).map(e => e.path); + console.log(formattedEntries, errors); - // todo: find error somewhere here and put it to errors array // If this collection has a "filter" property, filter entries accordingly const collectionFilter = collection.get('filter'); const filteredEntries = collectionFilter @@ -539,7 +530,6 @@ export class Backend { const groupedEntries = groupEntries(collection, extension, filteredEntries); return {entries: groupedEntries, errors}; } - // todo: return object { entries, errors } + change all other processEntries uses to just take entries return {entries: filteredEntries, errors}; } @@ -890,7 +880,6 @@ export class Backend { const format = resolveFormat(collection, entry); if (entry && entry.raw !== undefined) { const data = (format && attempt(format.fromFile.bind(format, entry.raw))) || {}; - // const data = (format && format.fromFile.bind(format, entry.raw)()) || {}; if (isError(data)) { entry = Object.assign(entry, { parseError: data.message }); } From 344417ba6b0cd4ed62aed6a5a61039074eb12b4d Mon Sep 17 00:00:00 2001 From: Martin Jagodic Date: Wed, 4 Sep 2024 15:16:05 +0200 Subject: [PATCH 06/10] refactor: cleanup --- packages/decap-cms-core/src/backend.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/decap-cms-core/src/backend.ts b/packages/decap-cms-core/src/backend.ts index c6dd832e64b9..22dbf9c23d95 100644 --- a/packages/decap-cms-core/src/backend.ts +++ b/packages/decap-cms-core/src/backend.ts @@ -517,7 +517,6 @@ export class Backend { const formattedEntries = entries.map(this.entryWithFormat(collection)); const errors = formattedEntries.filter(e => e.parseError).map(e => e.path); - console.log(formattedEntries, errors); // If this collection has a "filter" property, filter entries accordingly const collectionFilter = collection.get('filter'); From 7c9b170438af133e29641976c94b318718eff095 Mon Sep 17 00:00:00 2001 From: Martin Jagodic Date: Wed, 4 Sep 2024 15:17:42 +0200 Subject: [PATCH 07/10] refactor: format --- packages/decap-cms-core/src/backend.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/decap-cms-core/src/backend.ts b/packages/decap-cms-core/src/backend.ts index 22dbf9c23d95..ec462c4e2058 100644 --- a/packages/decap-cms-core/src/backend.ts +++ b/packages/decap-cms-core/src/backend.ts @@ -527,9 +527,9 @@ export class Backend { if (hasI18n(collection)) { const extension = selectFolderEntryExtension(collection); const groupedEntries = groupEntries(collection, extension, filteredEntries); - return {entries: groupedEntries, errors}; + return { entries: groupedEntries, errors }; } - return {entries: filteredEntries, errors}; + return { entries: filteredEntries, errors }; } async listEntries(collection: Collection) { From e3c97822adc51bbad208e78f151f9431523dc6e5 Mon Sep 17 00:00:00 2001 From: Martin Jagodic Date: Wed, 4 Sep 2024 15:26:37 +0200 Subject: [PATCH 08/10] feat: improve error messaging --- packages/decap-cms-core/src/backend.ts | 3 ++- packages/decap-cms-locales/src/en/index.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/decap-cms-core/src/backend.ts b/packages/decap-cms-core/src/backend.ts index ec462c4e2058..2d3c96414d18 100644 --- a/packages/decap-cms-core/src/backend.ts +++ b/packages/decap-cms-core/src/backend.ts @@ -516,7 +516,7 @@ export class Backend { ); const formattedEntries = entries.map(this.entryWithFormat(collection)); - const errors = formattedEntries.filter(e => e.parseError).map(e => e.path); + const errors = formattedEntries.filter(e => e.parseError).map(e => `${e.parseError}. In ${e.path}`); // If this collection has a "filter" property, filter entries accordingly const collectionFilter = collection.get('filter'); @@ -880,6 +880,7 @@ export class Backend { if (entry && entry.raw !== undefined) { const data = (format && attempt(format.fromFile.bind(format, entry.raw))) || {}; if (isError(data)) { + console.warn(data.message, '\n', data.stack); entry = Object.assign(entry, { parseError: data.message }); } diff --git a/packages/decap-cms-locales/src/en/index.js b/packages/decap-cms-locales/src/en/index.js index e7661a454c9d..5f2f6289e2ce 100644 --- a/packages/decap-cms-locales/src/en/index.js +++ b/packages/decap-cms-locales/src/en/index.js @@ -271,7 +271,7 @@ const en = { onFailToDelete: 'Failed to delete entry: %{details}', onFailToUpdateStatus: 'Failed to update status: %{details}', missingRequiredField: "Oops, you've missed a required field. Please complete before saving.", - duplicateFrontmatterKey: 'Duplicate key found in frontmatter %{details}', + duplicateFrontmatterKey: 'Duplicate key in frontmatter. %{details}', entrySaved: 'Entry saved', entryPublished: 'Entry published', entryUnpublished: 'Entry unpublished', From caa41f1f755d8d749453ec9f35f0dcdbb8aab25a Mon Sep 17 00:00:00 2001 From: Martin Jagodic Date: Wed, 4 Sep 2024 16:18:34 +0200 Subject: [PATCH 09/10] fix: pass unit tests --- .../decap-cms-backend-gitlab/src/__tests__/gitlab.spec.js | 4 +++- packages/decap-cms-core/src/__tests__/backend.spec.js | 8 ++++---- packages/decap-cms-core/src/actions/entries.ts | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/decap-cms-backend-gitlab/src/__tests__/gitlab.spec.js b/packages/decap-cms-backend-gitlab/src/__tests__/gitlab.spec.js index 4953ac3e4a0d..8df225359b10 100644 --- a/packages/decap-cms-backend-gitlab/src/__tests__/gitlab.spec.js +++ b/packages/decap-cms-backend-gitlab/src/__tests__/gitlab.spec.js @@ -432,6 +432,7 @@ describe('gitlab backend', () => { expect(entries).toEqual({ cursor: expect.any(Cursor), pagination: 1, + errors: [], entries: expect.arrayContaining( tree.map(file => expect.objectContaining({ path: file.path })), ), @@ -445,7 +446,7 @@ describe('gitlab backend', () => { tree.forEach(file => interceptFiles(backend, file.path)); interceptCollection(backend, collectionManyEntriesConfig, { repeat: 5 }); - const entries = await backend.listAllEntries(fromJS(collectionManyEntriesConfig)); + const { entries } = await backend.listAllEntries(fromJS(collectionManyEntriesConfig)); expect(entries).toEqual( expect.arrayContaining(tree.map(file => expect.objectContaining({ path: file.path }))), @@ -463,6 +464,7 @@ describe('gitlab backend', () => { entries: expect.arrayContaining( files.map(file => expect.objectContaining({ path: file.file })), ), + errors: [], }); expect(entries.entries).toHaveLength(2); }); diff --git a/packages/decap-cms-core/src/__tests__/backend.spec.js b/packages/decap-cms-core/src/__tests__/backend.spec.js index c673c19a01c4..bf9afc7da370 100644 --- a/packages/decap-cms-core/src/__tests__/backend.spec.js +++ b/packages/decap-cms-core/src/__tests__/backend.spec.js @@ -655,15 +655,15 @@ describe('Backend', () => { backend = new Backend(implementation, { config: {}, backendName: 'github' }); backend.listAllEntries = jest.fn(collection => { if (collection.get('name') === 'posts') { - return Promise.resolve(posts); + return Promise.resolve({entries: posts}); } if (collection.get('name') === 'pages') { - return Promise.resolve(pages); + return Promise.resolve({entries: pages}); } if (collection.get('name') === 'files') { - return Promise.resolve(files); + return Promise.resolve({entries: files}); } - return Promise.resolve([]); + return Promise.resolve({entries: []}); }); }); diff --git a/packages/decap-cms-core/src/actions/entries.ts b/packages/decap-cms-core/src/actions/entries.ts index 7dfe87f999cc..8f6b29967cc8 100644 --- a/packages/decap-cms-core/src/actions/entries.ts +++ b/packages/decap-cms-core/src/actions/entries.ts @@ -164,7 +164,7 @@ export async function getAllEntries(state: State, collection: Collection) { const provider: Backend = integration ? getIntegrationProvider(state.integrations, backend.getToken, integration) : backend; - const entries = await provider.listAllEntries(collection); + const { entries } = await provider.listAllEntries(collection); return entries; } From 6a0fca7aac17623eec94ab3e2e4ce334a059eb2e Mon Sep 17 00:00:00 2001 From: Martin Jagodic Date: Wed, 4 Sep 2024 16:21:29 +0200 Subject: [PATCH 10/10] refactor: format --- packages/decap-cms-core/src/__tests__/backend.spec.js | 8 ++++---- packages/decap-cms-core/src/backend.ts | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/decap-cms-core/src/__tests__/backend.spec.js b/packages/decap-cms-core/src/__tests__/backend.spec.js index bf9afc7da370..5826c0ddb332 100644 --- a/packages/decap-cms-core/src/__tests__/backend.spec.js +++ b/packages/decap-cms-core/src/__tests__/backend.spec.js @@ -655,15 +655,15 @@ describe('Backend', () => { backend = new Backend(implementation, { config: {}, backendName: 'github' }); backend.listAllEntries = jest.fn(collection => { if (collection.get('name') === 'posts') { - return Promise.resolve({entries: posts}); + return Promise.resolve({ entries: posts }); } if (collection.get('name') === 'pages') { - return Promise.resolve({entries: pages}); + return Promise.resolve({ entries: pages }); } if (collection.get('name') === 'files') { - return Promise.resolve({entries: files}); + return Promise.resolve({ entries: files }); } - return Promise.resolve({entries: []}); + return Promise.resolve({ entries: [] }); }); }); diff --git a/packages/decap-cms-core/src/backend.ts b/packages/decap-cms-core/src/backend.ts index 2d3c96414d18..7c3868b0c74c 100644 --- a/packages/decap-cms-core/src/backend.ts +++ b/packages/decap-cms-core/src/backend.ts @@ -516,7 +516,9 @@ export class Backend { ); const formattedEntries = entries.map(this.entryWithFormat(collection)); - const errors = formattedEntries.filter(e => e.parseError).map(e => `${e.parseError}. In ${e.path}`); + const errors = formattedEntries + .filter(e => e.parseError) + .map(e => `${e.parseError}. In ${e.path}`); // If this collection has a "filter" property, filter entries accordingly const collectionFilter = collection.get('filter');