Use attributes instead of group tags
This commit is contained in:
		
							parent
							
								
									c6165c251c
								
							
						
					
					
						commit
						46613c8500
					
				
							
								
								
									
										25
									
								
								src/blocks/attributeBlocks/numberBlock.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/blocks/attributeBlocks/numberBlock.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| import { Block } from "payload/types"; | ||||
| import { AttributeTypes, Collections } from "../../constants"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| 
 | ||||
| export const numberBlock: Block = { | ||||
|   slug: "numberBlock", | ||||
|   interfaceName: "NumberBlock", | ||||
|   labels: { singular: "Number attribute", plural: "Number attributes" }, | ||||
|   fields: [ | ||||
|     rowField([ | ||||
|       { | ||||
|         name: "name", | ||||
|         type: "relationship", | ||||
|         relationTo: Collections.Attributes, | ||||
|         filterOptions: () => ({ type: { equals: AttributeTypes.Number } }), | ||||
|         required: true, | ||||
|       }, | ||||
|       { | ||||
|         name: "number", | ||||
|         type: "number", | ||||
|         required: true, | ||||
|       }, | ||||
|     ]), | ||||
|   ], | ||||
| }; | ||||
							
								
								
									
										28
									
								
								src/blocks/attributeBlocks/tagsBlock.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/blocks/attributeBlocks/tagsBlock.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| import { Block } from "payload/types"; | ||||
| import { AttributeTypes, Collections } from "../../constants"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| 
 | ||||
| export const tagsBlock: Block = { | ||||
|   slug: "tagsBlock", | ||||
|   interfaceName: "TagsBlock", | ||||
|   labels: { singular: "Tags attribute", plural: "Tags attributes" }, | ||||
|   fields: [ | ||||
|     rowField([ | ||||
|       { | ||||
|         name: "name", | ||||
|         type: "relationship", | ||||
|         relationTo: Collections.Attributes, | ||||
|         filterOptions: () => ({ type: { equals: AttributeTypes.Tags } }), | ||||
|         required: true, | ||||
|       }, | ||||
|       { | ||||
|         name: "tags", | ||||
|         type: "relationship", | ||||
|         relationTo: Collections.Tags, | ||||
|         required: true, | ||||
|         hasMany: true, | ||||
|         minRows: 1, | ||||
|       }, | ||||
|     ]), | ||||
|   ], | ||||
| }; | ||||
							
								
								
									
										25
									
								
								src/blocks/attributeBlocks/textBlock.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/blocks/attributeBlocks/textBlock.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| import { Block } from "payload/types"; | ||||
| import { AttributeTypes, Collections } from "../../constants"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| 
 | ||||
| export const textBlock: Block = { | ||||
|   slug: "textBlock", | ||||
|   interfaceName: "TextBlock", | ||||
|   labels: { singular: "Text attribute", plural: "Text attributes" }, | ||||
|   fields: [ | ||||
|     rowField([ | ||||
|       { | ||||
|         name: "name", | ||||
|         type: "relationship", | ||||
|         relationTo: Collections.Attributes, | ||||
|         filterOptions: () => ({ type: { equals: AttributeTypes.Text } }), | ||||
|         required: true, | ||||
|       }, | ||||
|       { | ||||
|         name: "text", | ||||
|         type: "textarea", | ||||
|         required: true, | ||||
|       }, | ||||
|     ]), | ||||
|   ], | ||||
| }; | ||||
							
								
								
									
										51
									
								
								src/collections/Attributes/Attributes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/collections/Attributes/Attributes.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { mustBeAdmin } from "../../accesses/fields/mustBeAdmin"; | ||||
| import { AttributeTypes, CollectionGroups, Collections } from "../../constants"; | ||||
| import { iconField } from "../../fields/iconField/iconField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { slugField } from "../../fields/slugField/slugField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| 
 | ||||
| const fields = { | ||||
|   slug: "slug", | ||||
|   translations: "translations", | ||||
|   translationsName: "name", | ||||
|   icon: "icon", | ||||
|   type: "type", | ||||
| }; | ||||
| 
 | ||||
| export const Attributes: CollectionConfig = buildCollectionConfig({ | ||||
|   slug: Collections.Attributes, | ||||
|   labels: { singular: "Attribute", plural: "Attributes" }, | ||||
|   admin: { | ||||
|     group: CollectionGroups.Meta, | ||||
|     useAsTitle: fields.slug, | ||||
|     defaultColumns: [fields.slug, fields.icon, fields.type, fields.translations], | ||||
|   }, | ||||
|   fields: [ | ||||
|     rowField([ | ||||
|       slugField({ name: fields.slug }), | ||||
|       iconField({ name: fields.icon }), | ||||
|       { | ||||
|         name: fields.type, | ||||
|         type: "select", | ||||
|         access: { | ||||
|           update: mustBeAdmin, | ||||
|         }, | ||||
|         required: true, | ||||
|         options: Object.values(AttributeTypes).map((value) => ({ | ||||
|           label: value, | ||||
|           value: value, | ||||
|         })), | ||||
|       }, | ||||
|     ]), | ||||
|     translatedFields({ | ||||
|       name: fields.translations, | ||||
|       admin: { useAsTitle: fields.translationsName }, | ||||
|       required: true, | ||||
|       minRows: 1, | ||||
|       fields: [{ name: fields.translationsName, type: "text", required: true }], | ||||
|     }), | ||||
|   ], | ||||
| }); | ||||
| @ -1,4 +1,5 @@ | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { attributesField } from "../../fields/attributesField/attributesField"; | ||||
| import { creditsField } from "../../fields/creditsField/creditsField"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| @ -21,6 +22,7 @@ const fields = { | ||||
|   thumbnail: "thumbnail", | ||||
|   duration: "duration", | ||||
|   tags: "tags", | ||||
|   attributes: "attributes", | ||||
|   credits: "credits", | ||||
| }; | ||||
| 
 | ||||
| @ -72,6 +74,7 @@ export const Audios = buildCollectionConfig({ | ||||
|       ], | ||||
|     }), | ||||
|     tagsField({ name: fields.tags }), | ||||
|     attributesField({ name: fields.attributes }), | ||||
|     creditsField({ name: fields.credits }), | ||||
|   ], | ||||
| }); | ||||
|  | ||||
| @ -5,9 +5,9 @@ import { Audio } from "../../../types/collections"; | ||||
| import { CollectionEndpoint } from "../../../types/payload"; | ||||
| import { isNotEmpty, isValidPayloadImage, isValidPayloadMedia } from "../../../utils/asserts"; | ||||
| import { | ||||
|   convertAttributesToEndpointAttributes, | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertRTCToEndpointRTC, | ||||
|   convertTagsEndpointTagsGroups, | ||||
|   getLanguageId, | ||||
| } from "../../../utils/endpoints"; | ||||
| 
 | ||||
| @ -48,7 +48,7 @@ export const getByID: CollectionEndpoint = { | ||||
| 
 | ||||
| export const convertAudioToEndpointAudio = ({ | ||||
|   url, | ||||
|   tags, | ||||
|   attributes, | ||||
|   translations, | ||||
|   mimeType, | ||||
|   createdAt, | ||||
| @ -61,7 +61,7 @@ export const convertAudioToEndpointAudio = ({ | ||||
|   credits, | ||||
| }: Audio & PayloadMedia): EndpointAudio => ({ | ||||
|   url, | ||||
|   tagGroups: convertTagsEndpointTagsGroups(tags), | ||||
|   attributes: convertAttributesToEndpointAttributes(attributes), | ||||
|   createdAt, | ||||
|   filename, | ||||
|   filesize, | ||||
|  | ||||
| @ -7,6 +7,7 @@ import { | ||||
|   CollectionGroups, | ||||
|   Collections, | ||||
| } from "../../constants"; | ||||
| import { attributesField } from "../../fields/attributesField/attributesField"; | ||||
| import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; | ||||
| import { componentField } from "../../fields/componentField/componentField"; | ||||
| import { creditsField } from "../../fields/creditsField/creditsField"; | ||||
| @ -34,6 +35,7 @@ const fields = { | ||||
|   backgroundImage: "backgroundImage", | ||||
|   nature: "nature", | ||||
|   tags: "tags", | ||||
|   attributes: "attributes", | ||||
|   languages: "languages", | ||||
| 
 | ||||
|   translations: "translations", | ||||
| @ -189,6 +191,7 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|             ]), | ||||
| 
 | ||||
|             tagsField({ name: fields.tags }), | ||||
|             attributesField({ name: fields.attributes }), | ||||
| 
 | ||||
|             translatedFields({ | ||||
|               name: fields.translations, | ||||
|  | ||||
| @ -12,8 +12,8 @@ import { | ||||
|   isValidPayloadMedia, | ||||
| } from "../../../utils/asserts"; | ||||
| import { | ||||
|   convertAttributesToEndpointAttributes, | ||||
|   convertSourceToEndpointSource, | ||||
|   convertTagsEndpointTagsGroups, | ||||
|   getDomainFromUrl, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { convertAudioToEndpointAudio } from "../../Audios/endpoints/getByID"; | ||||
| @ -52,7 +52,7 @@ export const convertCollectibleToEndpointCollectible = ({ | ||||
|   releaseDate, | ||||
|   languages, | ||||
|   scans: rawScans, | ||||
|   tags, | ||||
|   attributes, | ||||
|   createdAt, | ||||
|   updatedAt, | ||||
|   scansEnabled, | ||||
| @ -72,7 +72,7 @@ export const convertCollectibleToEndpointCollectible = ({ | ||||
|     ...(isValidPayloadImage(backgroundImage) | ||||
|       ? { backgroundImage: convertImageToEndpointImage(backgroundImage) } | ||||
|       : {}), | ||||
|     tagGroups: convertTagsEndpointTagsGroups(tags), | ||||
|     attributes: convertAttributesToEndpointAttributes(attributes), | ||||
|     translations: | ||||
|       translations?.map(({ language, title, description, pretitle, subtitle }) => ({ | ||||
|         language: isPayloadType(language) ? language.id : language, | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { Collections } from "../../constants"; | ||||
| import { attributesField } from "../../fields/attributesField/attributesField"; | ||||
| import { creditsField } from "../../fields/creditsField/creditsField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { tagsField } from "../../fields/tagsField/tagsField"; | ||||
| @ -19,6 +20,7 @@ const fields = { | ||||
|   translationsSubtitle: "subtitle", | ||||
|   translationsDescription: "description", | ||||
|   tags: "tags", | ||||
|   attributes: "attributes", | ||||
|   credits: "credits", | ||||
| } as const satisfies Record<string, string>; | ||||
| 
 | ||||
| @ -64,6 +66,7 @@ export const Images = buildImageCollectionConfig({ | ||||
|       ], | ||||
|     }), | ||||
|     tagsField({ name: fields.tags }), | ||||
|     attributesField({ name: fields.attributes }), | ||||
|     creditsField({ name: fields.credits }), | ||||
|   ], | ||||
| }); | ||||
|  | ||||
| @ -5,9 +5,9 @@ import { Image } from "../../../types/collections"; | ||||
| import { CollectionEndpoint } from "../../../types/payload"; | ||||
| import { isNotEmpty, isValidPayloadImage } from "../../../utils/asserts"; | ||||
| import { | ||||
|   convertAttributesToEndpointAttributes, | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertRTCToEndpointRTC, | ||||
|   convertTagsEndpointTagsGroups, | ||||
|   getLanguageId, | ||||
| } from "../../../utils/endpoints"; | ||||
| 
 | ||||
| @ -50,7 +50,7 @@ export const convertImageToEndpointImage = ({ | ||||
|   url, | ||||
|   width, | ||||
|   height, | ||||
|   tags, | ||||
|   attributes, | ||||
|   translations, | ||||
|   mimeType, | ||||
|   createdAt, | ||||
| @ -63,7 +63,7 @@ export const convertImageToEndpointImage = ({ | ||||
|   url, | ||||
|   width, | ||||
|   height, | ||||
|   tagGroups: convertTagsEndpointTagsGroups(tags), | ||||
|   attributes: convertAttributesToEndpointAttributes(attributes), | ||||
|   createdAt, | ||||
|   filename, | ||||
|   filesize, | ||||
|  | ||||
| @ -4,6 +4,7 @@ import { sectionBlock } from "../../blocks/sectionBlock"; | ||||
| import { transcriptBlock } from "../../blocks/transcriptBlock"; | ||||
| import { QuickFilters, publishStatusFilters } from "../../components/QuickFilters"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { attributesField } from "../../fields/attributesField/attributesField"; | ||||
| import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; | ||||
| import { creditsField } from "../../fields/creditsField/creditsField"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| @ -24,6 +25,7 @@ const fields = { | ||||
|   backgroundImage: "backgroundImage", | ||||
|   translations: "translations", | ||||
|   tags: "tags", | ||||
|   attributes: "attributes", | ||||
|   sourceLanguage: "sourceLanguage", | ||||
|   pretitle: "pretitle", | ||||
|   title: "title", | ||||
| @ -89,6 +91,7 @@ export const Pages = buildVersionedCollectionConfig({ | ||||
|       }), | ||||
|     ]), | ||||
|     tagsField({ name: fields.tags }), | ||||
|     attributesField({ name: fields.attributes }), | ||||
|     translatedFields({ | ||||
|       name: fields.translations, | ||||
|       admin: { useAsTitle: fields.title, hasSourceLanguage: true }, | ||||
|  | ||||
| @ -11,10 +11,10 @@ import { EndpointPage, TableOfContentEntry } from "../../../sdk"; | ||||
| import { Page } from "../../../types/collections"; | ||||
| import { isNotEmpty, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; | ||||
| import { | ||||
|   convertAttributesToEndpointAttributes, | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertRTCToEndpointRTC, | ||||
|   convertSourceToEndpointSource, | ||||
|   convertTagsEndpointTagsGroups, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { convertImageToEndpointImage } from "../../Images/endpoints/getByID"; | ||||
| import { convertRecorderToEndpointRecorder } from "../../Recorders/endpoints/getByUsername"; | ||||
| @ -31,7 +31,7 @@ export const convertPageToEndpointPage = ({ | ||||
|   folders, | ||||
|   backgroundImage, | ||||
|   slug, | ||||
|   tags, | ||||
|   attributes, | ||||
|   thumbnail, | ||||
|   createdAt, | ||||
|   updatedAt, | ||||
| @ -42,7 +42,7 @@ export const convertPageToEndpointPage = ({ | ||||
|   ...(isValidPayloadImage(backgroundImage) | ||||
|     ? { backgroundImage: convertImageToEndpointImage(backgroundImage) } | ||||
|     : {}), | ||||
|   tagGroups: convertTagsEndpointTagsGroups(tags), | ||||
|   attributes: convertAttributesToEndpointAttributes(attributes), | ||||
|   translations: translations.map( | ||||
|     ({ content, language, sourceLanguage, title, pretitle, subtitle, summary, credits }) => ({ | ||||
|       language: isPayloadType(language) ? language.id : language, | ||||
|  | ||||
| @ -1,36 +1,16 @@ | ||||
| import payload from "payload"; | ||||
| import { CollectionBeforeChangeHook, CollectionConfig } from "payload/types"; | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { slugField } from "../../fields/slugField/slugField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| 
 | ||||
| const beforeChangeUpdateName: CollectionBeforeChangeHook = async ({ data }) => { | ||||
|   let name = data.slug; | ||||
| 
 | ||||
|   const parentId = data[fields.group]; | ||||
| 
 | ||||
|   if (parentId) { | ||||
|     const parent = await payload.findByID({ | ||||
|       collection: Collections.TagsGroups, | ||||
|       id: data[fields.group], | ||||
|     }); | ||||
|     name = `${parent.slug} / ${data.slug}`; | ||||
|   } | ||||
| 
 | ||||
|   return { | ||||
|     ...data, | ||||
|     [fields.name]: name, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const fields = { | ||||
|   slug: "slug", | ||||
|   name: "name", | ||||
|   translations: "translations", | ||||
|   translationsName: "name", | ||||
|   group: "group", | ||||
|   page: "page", | ||||
| }; | ||||
| 
 | ||||
| export const Tags: CollectionConfig = buildCollectionConfig({ | ||||
| @ -38,16 +18,27 @@ export const Tags: CollectionConfig = buildCollectionConfig({ | ||||
|   labels: { singular: "Tag", plural: "Tags" }, | ||||
|   admin: { | ||||
|     group: CollectionGroups.Meta, | ||||
|     useAsTitle: fields.name, | ||||
|     defaultColumns: [fields.slug, fields.group, fields.translations], | ||||
|     useAsTitle: fields.slug, | ||||
|     defaultColumns: [fields.slug, fields.translations], | ||||
|     hooks: { | ||||
|       beforeDuplicate: beforeDuplicateAddCopyTo(fields.slug), | ||||
|     }, | ||||
|   }, | ||||
|   hooks: { beforeChange: [beforeChangeUpdateName] }, | ||||
|   fields: [ | ||||
|     { name: fields.name, type: "text", admin: { readOnly: true, hidden: true } }, | ||||
|     slugField({ name: fields.slug }), | ||||
|     rowField([ | ||||
|       slugField({ name: fields.slug }), | ||||
|       { | ||||
|         name: fields.page, | ||||
|         type: "relationship", | ||||
|         relationTo: Collections.Pages, | ||||
|         admin: { | ||||
|           description: | ||||
|             "You can declare a 'definition' page where more information of the tag will be presented.\ | ||||
|           The selected page will then feature a new section\ | ||||
|           where elements tagged with this tag will be listed.", | ||||
|         }, | ||||
|       }, | ||||
|     ]), | ||||
|     translatedFields({ | ||||
|       name: fields.translations, | ||||
|       admin: { useAsTitle: fields.translationsName }, | ||||
| @ -55,11 +46,5 @@ export const Tags: CollectionConfig = buildCollectionConfig({ | ||||
|       minRows: 1, | ||||
|       fields: [{ name: fields.translationsName, type: "text", required: true }], | ||||
|     }), | ||||
|     { | ||||
|       name: fields.group, | ||||
|       type: "relationship", | ||||
|       required: true, | ||||
|       relationTo: Collections.TagsGroups, | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
|  | ||||
| @ -1,34 +0,0 @@ | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { iconField } from "../../fields/iconField/iconField"; | ||||
| import { slugField } from "../../fields/slugField/slugField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| 
 | ||||
| const fields = { | ||||
|   slug: "slug", | ||||
|   translations: "translations", | ||||
|   translationsName: "name", | ||||
|   icon: "icon", | ||||
| }; | ||||
| 
 | ||||
| export const TagsGroups: CollectionConfig = buildCollectionConfig({ | ||||
|   slug: Collections.TagsGroups, | ||||
|   labels: { singular: "Tags Group", plural: "Tags Groups" }, | ||||
|   admin: { | ||||
|     group: CollectionGroups.Meta, | ||||
|     useAsTitle: fields.slug, | ||||
|     defaultColumns: [fields.slug, fields.translations], | ||||
|   }, | ||||
|   fields: [ | ||||
|     slugField({ name: fields.slug }), | ||||
|     iconField({ name: fields.icon }), | ||||
|     translatedFields({ | ||||
|       name: fields.translations, | ||||
|       admin: { useAsTitle: fields.translationsName }, | ||||
|       required: true, | ||||
|       minRows: 1, | ||||
|       fields: [{ name: fields.translationsName, type: "text", required: true }], | ||||
|     }), | ||||
|   ], | ||||
| }); | ||||
| @ -1,4 +1,5 @@ | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { attributesField } from "../../fields/attributesField/attributesField"; | ||||
| import { componentField } from "../../fields/componentField/componentField"; | ||||
| import { creditsField } from "../../fields/creditsField/creditsField"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| @ -23,6 +24,7 @@ const fields = { | ||||
|   thumbnail: "thumbnail", | ||||
|   duration: "duration", | ||||
|   tags: "tags", | ||||
|   attributes: "attributes", | ||||
|   platform: "platform", | ||||
|   platformChannel: "channel", | ||||
|   platformViews: "views", | ||||
| @ -87,6 +89,7 @@ export const Videos = buildCollectionConfig({ | ||||
|       ], | ||||
|     }), | ||||
|     tagsField({ name: fields.tags }), | ||||
|     attributesField({ name: fields.attributes }), | ||||
|     creditsField({ name: fields.credits }), | ||||
|     componentField({ | ||||
|       name: fields.platform, | ||||
|  | ||||
| @ -13,9 +13,9 @@ import { | ||||
|   isValidPayloadMedia, | ||||
| } from "../../../utils/asserts"; | ||||
| import { | ||||
|   convertAttributesToEndpointAttributes, | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertRTCToEndpointRTC, | ||||
|   convertTagsEndpointTagsGroups, | ||||
|   getLanguageId, | ||||
| } from "../../../utils/endpoints"; | ||||
| 
 | ||||
| @ -56,7 +56,7 @@ export const getByID: CollectionEndpoint = { | ||||
| 
 | ||||
| export const convertVideoToEndpointVideo = ({ | ||||
|   url, | ||||
|   tags, | ||||
|   attributes, | ||||
|   translations, | ||||
|   mimeType, | ||||
|   createdAt, | ||||
| @ -71,7 +71,7 @@ export const convertVideoToEndpointVideo = ({ | ||||
|   credits, | ||||
| }: Video & PayloadMedia): EndpointVideo => ({ | ||||
|   url, | ||||
|   tagGroups: convertTagsEndpointTagsGroups(tags), | ||||
|   attributes: convertAttributesToEndpointAttributes(attributes), | ||||
|   createdAt, | ||||
|   filename, | ||||
|   filesize, | ||||
|  | ||||
| @ -4,26 +4,26 @@ import type { BreakBlock, SectionBlock, TranscriptBlock } from "./types/collecti | ||||
| // END MOCKING SECTION
 | ||||
| 
 | ||||
| export enum Collections { | ||||
|   Attributes = "attributes", | ||||
|   Audios = "audios", | ||||
|   ChronologyEvents = "chronology-events", | ||||
|   Collectibles = "collectibles", | ||||
|   CreditsRole = "credits-roles", | ||||
|   Currencies = "currencies", | ||||
|   Folders = "folders", | ||||
|   GenericContents = "generic-contents", | ||||
|   Images = "images", | ||||
|   Languages = "languages", | ||||
|   MediaThumbnails = "media-thumbnails", | ||||
|   Pages = "pages", | ||||
|   Recorders = "recorders", | ||||
|   Folders = "folders", | ||||
|   Tags = "tags", | ||||
|   TagsGroups = "tags-groups", | ||||
|   Images = "images", | ||||
|   Wordings = "wordings", | ||||
|   Collectibles = "collectibles", | ||||
|   GenericContents = "generic-contents", | ||||
|   WebsiteConfig = "website-config", | ||||
|   Videos = "videos", | ||||
|   VideosSubtitles = "videos-subtitles", | ||||
|   VideosChannels = "videos-channels", | ||||
|   MediaThumbnails = "media-thumbnails", | ||||
|   Scans = "scans", | ||||
|   CreditsRole = "credits-roles", | ||||
|   Tags = "tags", | ||||
|   Videos = "videos", | ||||
|   VideosChannels = "videos-channels", | ||||
|   VideosSubtitles = "videos-subtitles", | ||||
|   Wordings = "wordings", | ||||
|   WebsiteConfig = "website-config", | ||||
| } | ||||
| 
 | ||||
| export enum CollectionGroups { | ||||
| @ -80,6 +80,12 @@ export enum CollectionStatus { | ||||
|   Published = "published", | ||||
| } | ||||
| 
 | ||||
| export enum AttributeTypes { | ||||
|   Number = "Number", | ||||
|   Text = "Text", | ||||
|   Tags = "Tags", | ||||
| } | ||||
| 
 | ||||
| /* RICH TEXT */ | ||||
| 
 | ||||
| export type RichTextContent = { | ||||
|  | ||||
							
								
								
									
										12
									
								
								src/fields/attributesField/attributesField.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/fields/attributesField/attributesField.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| import { BlockField } from "payload/dist/fields/config/types"; | ||||
| import { numberBlock } from "../../blocks/attributeBlocks/numberBlock"; | ||||
| import { tagsBlock } from "../../blocks/attributeBlocks/tagsBlock"; | ||||
| import { textBlock } from "../../blocks/attributeBlocks/textBlock"; | ||||
| 
 | ||||
| type AttributesFieldProps = Omit<BlockField, "type" | "blocks">; | ||||
| 
 | ||||
| export const attributesField = ({ ...props }: AttributesFieldProps): BlockField => ({ | ||||
|   ...props, | ||||
|   type: "blocks", | ||||
|   blocks: [tagsBlock, numberBlock, textBlock], | ||||
| }); | ||||
| @ -4,6 +4,7 @@ import { cloudStorage } from "@payloadcms/plugin-cloud-storage"; | ||||
| import path from "path"; | ||||
| import { buildConfig } from "payload/config"; | ||||
| import { sftpAdapter } from "payloadcms-sftp-storage"; | ||||
| import { Attributes } from "./collections/Attributes/Attributes"; | ||||
| import { Audios } from "./collections/Audios/Audios"; | ||||
| import { ChronologyEvents } from "./collections/ChronologyEvents/ChronologyEvents"; | ||||
| import { Collectibles } from "./collections/Collectibles/Collectibles"; | ||||
| @ -13,15 +14,14 @@ import { Folders } from "./collections/Folders/Folders"; | ||||
| import { GenericContents } from "./collections/GenericContents/GenericContents"; | ||||
| import { Images } from "./collections/Images/Images"; | ||||
| import { Languages } from "./collections/Languages/Languages"; | ||||
| import { MediaThumbnails } from "./collections/MediaThumbnails/MediaThumbnails"; | ||||
| import { Pages } from "./collections/Pages/Pages"; | ||||
| import { Recorders } from "./collections/Recorders/Recorders"; | ||||
| import { Scans } from "./collections/Scans/Scans"; | ||||
| import { Tags } from "./collections/Tags/Tags"; | ||||
| import { TagsGroups } from "./collections/TagsGroups/TagsGroups"; | ||||
| import { Videos } from "./collections/Videos/Videos"; | ||||
| import { VideosChannels } from "./collections/VideosChannels/VideosChannels"; | ||||
| import { VideosSubtitles } from "./collections/VideosSubtitles/VideosSubtitles"; | ||||
| import { MediaThumbnails } from "./collections/VideosThumbnails/VideosThumbnails"; | ||||
| import { WebsiteConfig } from "./collections/WebsiteConfig/WebsiteConfig"; | ||||
| import { Wordings } from "./collections/Wordings/Wordings"; | ||||
| import { Icon } from "./components/Icon"; | ||||
| @ -68,7 +68,7 @@ export default buildConfig({ | ||||
|     Scans, | ||||
| 
 | ||||
|     Tags, | ||||
|     TagsGroups, | ||||
|     Attributes, | ||||
|     CreditsRoles, | ||||
|     Recorders, | ||||
|     Languages, | ||||
|  | ||||
							
								
								
									
										31
									
								
								src/sdk.ts
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								src/sdk.ts
									
									
									
									
									
								
							| @ -1,4 +1,5 @@ | ||||
| import { | ||||
|   AttributeTypes, | ||||
|   CollectibleBindingTypes, | ||||
|   CollectibleNature, | ||||
|   CollectiblePageOrders, | ||||
| @ -173,22 +174,42 @@ export type EndpointWording = { | ||||
| 
 | ||||
| export type EndpointTag = { | ||||
|   slug: string; | ||||
|   page?: EndpointPage; | ||||
|   translations: { | ||||
|     language: string; | ||||
|     name: string; | ||||
|   }[]; | ||||
| }; | ||||
| 
 | ||||
| export type EndpointTagsGroup = { | ||||
| export type EndpointGenericAttribute = { | ||||
|   slug: string; | ||||
|   icon: string; | ||||
|   translations: { | ||||
|     language: string; | ||||
|     name: string; | ||||
|   }[]; | ||||
|   tags: EndpointTag[]; | ||||
| }; | ||||
| 
 | ||||
| export type EndpointNumberAttribute = EndpointGenericAttribute & { | ||||
|   type: AttributeTypes.Number; | ||||
|   value: number; | ||||
| }; | ||||
| 
 | ||||
| export type EndpointTextAttribute = EndpointGenericAttribute & { | ||||
|   type: AttributeTypes.Text; | ||||
|   value: string; | ||||
| }; | ||||
| 
 | ||||
| export type EndpointTagsAttribute = EndpointGenericAttribute & { | ||||
|   type: AttributeTypes.Tags; | ||||
|   value: EndpointTag[]; | ||||
| }; | ||||
| 
 | ||||
| export type EndpointAttribute = | ||||
|   | EndpointNumberAttribute | ||||
|   | EndpointTextAttribute | ||||
|   | EndpointTagsAttribute; | ||||
| 
 | ||||
| export type EndpointRole = { | ||||
|   icon: string; | ||||
|   translations: { | ||||
| @ -205,7 +226,7 @@ export type EndpointCredit = { | ||||
| export type EndpointPage = { | ||||
|   slug: string; | ||||
|   thumbnail?: EndpointImage; | ||||
|   tagGroups: EndpointTagsGroup[]; | ||||
|   attributes: EndpointAttribute[]; | ||||
|   backgroundImage?: EndpointImage; | ||||
|   translations: { | ||||
|     language: string; | ||||
| @ -234,7 +255,7 @@ export type EndpointCollectible = { | ||||
|     subtitle?: string; | ||||
|     description?: RichTextContent; | ||||
|   }[]; | ||||
|   tagGroups: EndpointTagsGroup[]; | ||||
|   attributes: EndpointAttribute[]; | ||||
|   releaseDate?: string; | ||||
|   languages: string[]; | ||||
|   backgroundImage?: EndpointImage; | ||||
| @ -458,7 +479,7 @@ export type EndpointMedia = { | ||||
|   filesize: number; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
|   tagGroups: EndpointTagsGroup[]; | ||||
|   attributes: EndpointAttribute[]; | ||||
|   translations: { | ||||
|     language: string; | ||||
|     pretitle?: string; | ||||
|  | ||||
| @ -75,6 +75,9 @@ html[data-theme="light"] { | ||||
| } | ||||
| 
 | ||||
| .blocks-field__block-pill-cueBlock + .section-title, | ||||
| .blocks-field__block-pill-tagsBlock + .section-title, | ||||
| .blocks-field__block-pill-textBlock + .section-title, | ||||
| .blocks-field__block-pill-numberBlock + .section-title, | ||||
| .blocks-field__block-pill-pageRange + .section-title, | ||||
| .blocks-field__block-pill-timeRange + .section-title, | ||||
| .blocks-field__block-pill-urlBlock + .section-title, | ||||
|  | ||||
| @ -32,7 +32,7 @@ export interface Config { | ||||
|     "videos-channels": VideosChannel; | ||||
|     scans: Scan; | ||||
|     tags: Tag; | ||||
|     "tags-groups": TagsGroup; | ||||
|     attributes: Attribute; | ||||
|     "credits-roles": CreditsRole; | ||||
|     recorders: Recorder; | ||||
|     languages: Language; | ||||
| @ -56,6 +56,7 @@ export interface Page { | ||||
|   thumbnail?: string | Image | null; | ||||
|   backgroundImage?: string | Image | null; | ||||
|   tags?: (string | Tag)[] | null; | ||||
|   attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     sourceLanguage: string | Language; | ||||
| @ -133,6 +134,7 @@ export interface Image { | ||||
|       }[] | ||||
|     | null; | ||||
|   tags?: (string | Tag)[] | null; | ||||
|   attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null; | ||||
|   credits?: Credits; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| @ -175,25 +177,36 @@ export interface Language { | ||||
|  */ | ||||
| export interface Tag { | ||||
|   id: string; | ||||
|   name?: string | null; | ||||
|   slug: string; | ||||
|   page?: (string | null) | Page; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     name: string; | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   group: string | TagsGroup; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "tags-groups". | ||||
|  * via the `definition` "TagsBlock". | ||||
|  */ | ||||
| export interface TagsGroup { | ||||
| export interface TagsBlock { | ||||
|   name: string | Attribute; | ||||
|   tags: (string | Tag)[]; | ||||
|   id?: string | null; | ||||
|   blockName?: string | null; | ||||
|   blockType: "tagsBlock"; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "attributes". | ||||
|  */ | ||||
| export interface Attribute { | ||||
|   id: string; | ||||
|   slug: string; | ||||
|   icon?: string | null; | ||||
|   type: "Number" | "Text" | "Tags"; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     name: string; | ||||
| @ -202,6 +215,28 @@ export interface TagsGroup { | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "NumberBlock". | ||||
|  */ | ||||
| export interface NumberBlock { | ||||
|   name: string | Attribute; | ||||
|   number: number; | ||||
|   id?: string | null; | ||||
|   blockName?: string | null; | ||||
|   blockType: "numberBlock"; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "TextBlock". | ||||
|  */ | ||||
| export interface TextBlock { | ||||
|   name: string | Attribute; | ||||
|   text: string; | ||||
|   id?: string | null; | ||||
|   blockName?: string | null; | ||||
|   blockType: "textBlock"; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "credits-roles". | ||||
| @ -318,6 +353,7 @@ export interface Collectible { | ||||
|   nature: "Physical" | "Digital"; | ||||
|   languages?: (string | Language)[] | null; | ||||
|   tags?: (string | Tag)[] | null; | ||||
|   attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     pretitle?: string | null; | ||||
| @ -582,6 +618,7 @@ export interface Audio { | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   tags?: (string | Tag)[] | null; | ||||
|   attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null; | ||||
|   credits?: Credits; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| @ -657,6 +694,7 @@ export interface Video { | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   tags?: (string | Tag)[] | null; | ||||
|   attributes?: (TagsBlock | NumberBlock | TextBlock)[] | null; | ||||
|   credits?: Credits; | ||||
|   platformEnabled?: boolean | null; | ||||
|   platform?: { | ||||
|  | ||||
| @ -2,9 +2,11 @@ import { convertAudioToEndpointAudio } from "../collections/Audios/endpoints/get | ||||
| import { convertCollectibleToEndpointCollectible } from "../collections/Collectibles/endpoints/getBySlugEndpoint"; | ||||
| import { convertFolderToEndpointFolder } from "../collections/Folders/endpoints/getBySlugEndpoint"; | ||||
| import { convertImageToEndpointImage } from "../collections/Images/endpoints/getByID"; | ||||
| import { convertPageToEndpointPage } from "../collections/Pages/endpoints/getBySlugEndpoint"; | ||||
| import { convertRecorderToEndpointRecorder } from "../collections/Recorders/endpoints/getByUsername"; | ||||
| import { convertVideoToEndpointVideo } from "../collections/Videos/endpoints/getByID"; | ||||
| import { | ||||
|   AttributeTypes, | ||||
|   RichTextBreakBlock, | ||||
|   RichTextContent, | ||||
|   RichTextSectionBlock, | ||||
| @ -18,11 +20,11 @@ import { | ||||
|   isUploadNodeVideoNode, | ||||
| } from "../constants"; | ||||
| import { | ||||
|   EndpointAttribute, | ||||
|   EndpointCredit, | ||||
|   EndpointRole, | ||||
|   EndpointSource, | ||||
|   EndpointTag, | ||||
|   EndpointTagsGroup, | ||||
| } from "../sdk"; | ||||
| import { | ||||
|   Audio, | ||||
| @ -32,10 +34,15 @@ import { | ||||
|   Folder, | ||||
|   Image, | ||||
|   Language, | ||||
|   NumberBlock, | ||||
|   Tag, | ||||
|   TagsBlock, | ||||
|   TextBlock, | ||||
|   Video, | ||||
| } from "../types/collections"; | ||||
| import { | ||||
|   isDefined, | ||||
|   isEmpty, | ||||
|   isPayloadArrayType, | ||||
|   isPayloadType, | ||||
|   isPublished, | ||||
| @ -43,45 +50,14 @@ import { | ||||
|   isValidPayloadMedia, | ||||
| } from "./asserts"; | ||||
| 
 | ||||
| export const convertTagsEndpointTagsGroups = ( | ||||
|   tags: (string | Tag)[] | null | undefined | ||||
| ): EndpointTagsGroup[] => { | ||||
|   if (!isPayloadArrayType(tags)) { | ||||
|     return []; | ||||
|   } | ||||
| 
 | ||||
|   const groups: EndpointTagsGroup[] = []; | ||||
| 
 | ||||
|   tags.forEach(({ translations, slug, group }) => { | ||||
|     if (isPayloadType(group)) { | ||||
|       const existingGroup = groups.find((existingGroup) => existingGroup.slug === group.slug); | ||||
| 
 | ||||
|       const endpointTag: EndpointTag = { | ||||
|         slug, | ||||
|         translations: translations.map(({ language, name }) => ({ | ||||
|           language: isPayloadType(language) ? language.id : language, | ||||
|           name, | ||||
|         })), | ||||
|       }; | ||||
| 
 | ||||
|       if (existingGroup) { | ||||
|         existingGroup.tags.push(endpointTag); | ||||
|       } else { | ||||
|         groups.push({ | ||||
|           slug: group.slug, | ||||
|           icon: group.icon ?? "material-symbols:category-outline", | ||||
|           tags: [endpointTag], | ||||
|           translations: group.translations.map(({ language, name }) => ({ | ||||
|             language: isPayloadType(language) ? language.id : language, | ||||
|             name, | ||||
|           })), | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   return groups; | ||||
| }; | ||||
| const convertTagToEndpointTag = ({ slug, page, translations }: Tag): EndpointTag => ({ | ||||
|   slug, | ||||
|   ...(page && isPayloadType(page) ? { page: convertPageToEndpointPage(page) } : {}), | ||||
|   translations: translations.map(({ language, name }) => ({ | ||||
|     language: isPayloadType(language) ? language.id : language, | ||||
|     name, | ||||
|   })), | ||||
| }); | ||||
| 
 | ||||
| export const convertRTCToEndpointRTC = ( | ||||
|   { root: { children, ...others } }: RichTextContent, | ||||
| @ -233,3 +209,66 @@ export const convertCreditsToEndpointCredits = (credits?: Credits | null): Endpo | ||||
|       }, | ||||
|     ]; | ||||
|   }) ?? []; | ||||
| 
 | ||||
| export const convertAttributesToEndpointAttributes = ( | ||||
|   attributes: (TagsBlock | NumberBlock | TextBlock)[] | null | undefined | ||||
| ): EndpointAttribute[] => | ||||
|   attributes?.map(convertAttributeToEndpointAttribute).filter(isDefined) ?? []; | ||||
| 
 | ||||
| const convertAttributeToEndpointAttribute = ( | ||||
|   attribute: TagsBlock | NumberBlock | TextBlock | ||||
| ): EndpointAttribute | undefined => { | ||||
|   switch (attribute.blockType) { | ||||
|     case "numberBlock": { | ||||
|       const { name, number } = attribute; | ||||
|       if (!isPayloadType(name)) return; | ||||
|       const { slug, icon, translations } = name; | ||||
|       return { | ||||
|         slug, | ||||
|         icon: icon ?? "material-symbols:category-outline", | ||||
|         translations: translations.map(({ language, name }) => ({ | ||||
|           language: isPayloadType(language) ? language.id : language, | ||||
|           name, | ||||
|         })), | ||||
|         type: AttributeTypes.Number, | ||||
|         value: number, | ||||
|       }; | ||||
|     } | ||||
| 
 | ||||
|     case "textBlock": { | ||||
|       const { name, text } = attribute; | ||||
|       if (!isPayloadType(name)) return; | ||||
|       if (isEmpty(text)) return; | ||||
|       const { slug, icon, translations } = name; | ||||
|       return { | ||||
|         slug, | ||||
|         icon: icon ?? "material-symbols:category-outline", | ||||
|         translations: translations.map(({ language, name }) => ({ | ||||
|           language: isPayloadType(language) ? language.id : language, | ||||
|           name, | ||||
|         })), | ||||
|         type: AttributeTypes.Text, | ||||
|         value: text, | ||||
|       }; | ||||
|     } | ||||
| 
 | ||||
|     case "tagsBlock": { | ||||
|       const { name, tags } = attribute; | ||||
|       if (!isPayloadType(name)) return; | ||||
|       if (!isPayloadArrayType(tags)) return; | ||||
|       if (tags.length === 0) return; | ||||
|       const { slug, icon, translations } = name; | ||||
| 
 | ||||
|       return { | ||||
|         slug, | ||||
|         icon: icon ?? "material-symbols:category-outline", | ||||
|         translations: translations.map(({ language, name }) => ({ | ||||
|           language: isPayloadType(language) ? language.id : language, | ||||
|           name, | ||||
|         })), | ||||
|         type: AttributeTypes.Tags, | ||||
|         value: tags.map(convertTagToEndpointTag), | ||||
|       }; | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint