Much stricter ts
This commit is contained in:
		
							parent
							
								
									f56ba4675f
								
							
						
					
					
						commit
						f28a928442
					
				
							
								
								
									
										9
									
								
								src/accesses/collections/mustBeAdmin.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/accesses/collections/mustBeAdmin.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| import { Access } from "payload/config"; | ||||
| import { RecordersRoles } from "../../constants"; | ||||
| import { Recorder } from "../../types/collections"; | ||||
| import { isDefined, isUndefined } from "../../utils/asserts"; | ||||
| 
 | ||||
| export const mustBeAdmin: Access<unknown, Recorder> = ({ req: { user } }): boolean => { | ||||
|   if (isUndefined(user)) return false; | ||||
|   return isDefined(user.role) && user.role.includes(RecordersRoles.Admin); | ||||
| }; | ||||
| @ -1,11 +1,10 @@ | ||||
| import { Access } from "payload/config"; | ||||
| import { Recorder } from "../../types/collections"; | ||||
| import { RecordersRoles } from "../../constants"; | ||||
| import { Recorder } from "../../types/collections"; | ||||
| import { isUndefined } from "../../utils/asserts"; | ||||
| 
 | ||||
| export const mustBeAdminOrSelf: Access = ({ req }) => { | ||||
|   const user = req.user as Recorder | undefined; | ||||
| export const mustBeAdminOrSelf: Access<unknown, Recorder> = ({ req: { user } }) => { | ||||
|   if (isUndefined(user)) return false; | ||||
|   if (user.role.includes(RecordersRoles.Admin)) return true; | ||||
|   if (user.role?.includes(RecordersRoles.Admin)) return true; | ||||
|   return { id: { equals: user.id } }; | ||||
| }; | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| import { Access } from "payload/config"; | ||||
| import { Recorder } from "../../types/collections"; | ||||
| import { isUndefined } from "../../utils/asserts"; | ||||
| import { isDefined, isUndefined } from "../../utils/asserts"; | ||||
| 
 | ||||
| export const mustHaveAtLeastOneRole = ({ req }): boolean => { | ||||
|   const user = req.user as Recorder | undefined; | ||||
| export const mustHaveAtLeastOneRole: Access<unknown, Recorder> = ({ req: { user } }): boolean => { | ||||
|   if (isUndefined(user)) return false; | ||||
|   return user.role.length > 0; | ||||
|   return isDefined(user.role) && user.role.length > 0; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										9
									
								
								src/accesses/fields/mustBeAdmin.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/accesses/fields/mustBeAdmin.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| import { FieldAccess } from "payload/types"; | ||||
| import { RecordersRoles } from "../../constants"; | ||||
| import { Recorder } from "../../types/collections"; | ||||
| import { isDefined, isUndefined } from "../../utils/asserts"; | ||||
| 
 | ||||
| export const mustBeAdmin: FieldAccess<any, any, Recorder> = ({ req: { user } }): boolean => { | ||||
|   if (isUndefined(user)) return false; | ||||
|   return isDefined(user.role) && user.role.includes(RecordersRoles.Admin); | ||||
| }; | ||||
| @ -1,9 +0,0 @@ | ||||
| import { Recorder } from "../types/collections"; | ||||
| import { RecordersRoles } from "../constants"; | ||||
| import { isUndefined } from "../utils/asserts"; | ||||
| 
 | ||||
| export const mustBeAdmin = ({ req }): boolean => { | ||||
|   const user = req.user as Recorder | undefined; | ||||
|   if (isUndefined(user)) return false; | ||||
|   return user.role.includes(RecordersRoles.Admin); | ||||
| }; | ||||
| @ -1,5 +1,5 @@ | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { mustBeAdmin } from "../../accesses/mustBeAdmin"; | ||||
| import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; | ||||
| import { slugField } from "../../fields/slugField/slugField"; | ||||
|  | ||||
| @ -1,8 +1,17 @@ | ||||
| import { Collections } from "../../../constants"; | ||||
| import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { ChronologyEra } from "../../../types/collections"; | ||||
| import { StrapiLanguage } from "../../../types/strapi"; | ||||
| import { isUndefined } from "../../../utils/asserts"; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<ChronologyEra>({ | ||||
| type StrapiChronologyEra = { | ||||
|   slug: string; | ||||
|   starting_year: number; | ||||
|   ending_year: number; | ||||
|   title: { title: string; language: StrapiLanguage; description?: string }[]; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<ChronologyEra, StrapiChronologyEra>({ | ||||
|   strapi: { | ||||
|     collection: "chronology-eras", | ||||
|     params: { | ||||
| @ -15,11 +24,15 @@ export const importFromStrapi = createStrapiImportEndpoint<ChronologyEra>({ | ||||
|       slug, | ||||
|       startingYear: starting_year, | ||||
|       endingYear: ending_year, | ||||
|       translations: titles.map(({ language, title, description }) => ({ | ||||
|         language: language.data.attributes.code, | ||||
|         title, | ||||
|         description, | ||||
|       })), | ||||
|       translations: titles.map(({ language, title, description }) => { | ||||
|         if (isUndefined(language.data)) | ||||
|           throw new Error("Language is undefined for one of the translations"); | ||||
|         return { | ||||
|           language: language.data?.attributes.code, | ||||
|           title, | ||||
|           description, | ||||
|         }; | ||||
|       }), | ||||
|     }), | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| @ -1,9 +1,14 @@ | ||||
| import { CollectionBeforeValidateHook } from "payload/types"; | ||||
| import { ChronologyEra } from "../../../types/collections"; | ||||
| import { isUndefined } from "../../../utils/asserts"; | ||||
| 
 | ||||
| export const beforeValidateEndingGreaterThanStarting: CollectionBeforeValidateHook< | ||||
|   ChronologyEra | ||||
| > = async ({ data: { startingYear, endingYear } }) => { | ||||
| > = async ({ data }) => { | ||||
|   if (isUndefined(data)) throw new Error("The data is undefined"); | ||||
|   const { startingYear, endingYear } = data; | ||||
|   if (isUndefined(endingYear)) throw new Error("Ending year is undefined"); | ||||
|   if (isUndefined(startingYear)) throw new Error("Starting year is undefined"); | ||||
|   if (endingYear < startingYear) { | ||||
|     throw new Error("The ending year cannot be before the starting year."); | ||||
|   } | ||||
|  | ||||
| @ -2,11 +2,16 @@ import payload from "payload"; | ||||
| import { CollectionBeforeValidateHook } from "payload/types"; | ||||
| import { Collections } from "../../../constants"; | ||||
| import { ChronologyEra } from "../../../types/collections"; | ||||
| import { hasIntersection } from "../../../utils/asserts"; | ||||
| import { hasIntersection, isUndefined } from "../../../utils/asserts"; | ||||
| 
 | ||||
| export const beforeValidateNoIntersection: CollectionBeforeValidateHook<ChronologyEra> = async ({ | ||||
|   data: { startingYear, endingYear }, | ||||
|   data, | ||||
| }) => { | ||||
|   if (isUndefined(data)) throw new Error("The data is undefined"); | ||||
|   const { startingYear, endingYear } = data; | ||||
|   if (isUndefined(endingYear)) throw new Error("Ending year is undefined"); | ||||
|   if (isUndefined(startingYear)) throw new Error("Starting year is undefined"); | ||||
| 
 | ||||
|   const otherEras = await payload.find({ | ||||
|     collection: Collections.ChronologyEras, | ||||
|     limit: 100, | ||||
|  | ||||
| @ -72,6 +72,7 @@ export const ChronologyItems: CollectionConfig = buildVersionedCollectionConfig( | ||||
|         if (!DateTime.fromObject({ year, month, day }).isValid) { | ||||
|           return `The given date (${stringDate}) is not a valid date.`; | ||||
|         } | ||||
|         return true; | ||||
|       }, | ||||
|       fields: [ | ||||
|         { | ||||
|  | ||||
| @ -1,8 +1,24 @@ | ||||
| import { Collections } from "../../../constants"; | ||||
| import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { ChronologyItem } from "../../../types/collections"; | ||||
| import { StrapiLanguage } from "../../../types/strapi"; | ||||
| import { isUndefined } from "../../../utils/asserts"; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<ChronologyItem>({ | ||||
| type StrapiChronologyItem = { | ||||
|   year: number; | ||||
|   month?: number; | ||||
|   day?: number; | ||||
|   events: { | ||||
|     translations: { | ||||
|       title?: string; | ||||
|       description?: string; | ||||
|       note?: string; | ||||
|       language: StrapiLanguage; | ||||
|     }[]; | ||||
|   }[]; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<ChronologyItem, StrapiChronologyItem>({ | ||||
|   strapi: { | ||||
|     collection: "chronology-items", | ||||
|     params: { | ||||
| @ -14,16 +30,20 @@ export const importFromStrapi = createStrapiImportEndpoint<ChronologyItem>({ | ||||
|     convert: ({ year, month, day, events }, user) => ({ | ||||
|       date: { year, month, day }, | ||||
|       events: events.map((event) => ({ | ||||
|         translations: event.translations.map(({ title, description, note, language }) => ({ | ||||
|           title, | ||||
|           description, | ||||
|           note, | ||||
|           language: language.data.attributes.code, | ||||
|           sourceLanguage: "en", | ||||
|           ...(language.data.attributes.code === "en" | ||||
|             ? { transcribers: [user.id] } | ||||
|             : { translators: [user.id] }), | ||||
|         })), | ||||
|         translations: event.translations.map(({ title, description, note, language }) => { | ||||
|           if (isUndefined(language.data)) | ||||
|             throw new Error("A language is required for a chronology item event translation"); | ||||
|           return { | ||||
|             title, | ||||
|             description, | ||||
|             note, | ||||
|             language: language.data.attributes.code, | ||||
|             sourceLanguage: "en", | ||||
|             ...(language.data.attributes.code === "en" | ||||
|               ? { transcribers: [user.id] } | ||||
|               : { translators: [user.id] }), | ||||
|           }; | ||||
|         }), | ||||
|       })), | ||||
|     }), | ||||
|   }, | ||||
|  | ||||
| @ -6,8 +6,12 @@ export const beforeValidatePopulateNameField: FieldHook< | ||||
|   ChronologyItem, | ||||
|   ChronologyItem["name"], | ||||
|   ChronologyItem | ||||
| > = ({ data: { date } }) => { | ||||
|   if (isUndefined(date?.year)) return "????-??-??"; | ||||
| > = ({ data }) => { | ||||
|   if (isUndefined(data)) { | ||||
|     return "????-??-??"; | ||||
|   } | ||||
|   const { date } = data; | ||||
|   if (isUndefined(date) || isUndefined(date?.year)) return "????-??-??"; | ||||
|   const { year, month, day } = date; | ||||
|   let result = String(year).padStart(5, " "); | ||||
|   if (isDefined(month)) { | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { text } from "payload/dist/fields/validations"; | ||||
| import { mustBeAdmin } from "../../accesses/mustBeAdmin"; | ||||
| import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { importFromStrapi } from "./endpoints/importFromStrapi"; | ||||
|  | ||||
| @ -2,7 +2,12 @@ import { Collections } from "../../../constants"; | ||||
| import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { Language } from "../../../types/collections"; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Language>({ | ||||
| type StrapiLanguage = { | ||||
|   code: string; | ||||
|   name: string; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Language, StrapiLanguage>({ | ||||
|   strapi: { | ||||
|     collection: "currencies", | ||||
|     params: {}, | ||||
|  | ||||
| @ -1,11 +1,11 @@ | ||||
| import payload from "payload"; | ||||
| import { mustBeAdmin } from "../../accesses/mustBeAdmin"; | ||||
| import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { QuickFilters } from "../../components/QuickFilters"; | ||||
| import { CollectionGroups, Collections, KeysTypes, LanguageCodes } from "../../constants"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; | ||||
| import { Key } from "../../types/collections"; | ||||
| import { isDefined } from "../../utils/asserts"; | ||||
| import { isDefined, isUndefined } from "../../utils/asserts"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { importFromStrapi } from "./endpoints/importFromStrapi"; | ||||
| 
 | ||||
| @ -58,15 +58,15 @@ export const Keys = buildCollectionConfig({ | ||||
|   }, | ||||
|   hooks: { | ||||
|     beforeValidate: [ | ||||
|       async ({ data: { name, type } }) => { | ||||
|       async ({ data }) => { | ||||
|         if (isUndefined(data)) return; | ||||
|         const { name, type } = data; | ||||
|         const result = await payload.find({ | ||||
|           collection: Collections.Keys, | ||||
|           where: { name: { equals: name }, type: { equals: type } }, | ||||
|         }); | ||||
|         if (result.docs.length > 0) { | ||||
|           throw new Error( | ||||
|             `A Key of type "${KeysTypes[type]}" already exists with the name "${name}"` | ||||
|           ); | ||||
|           throw new Error(`A Key of type "${type}" already exists with the name "${name}"`); | ||||
|         } | ||||
|       }, | ||||
|     ], | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| import payload from "payload"; | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { Collections } from "../../../constants"; | ||||
| import { | ||||
|   getAllStrapiEntries, | ||||
|   importStrapiEntries, | ||||
| } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { Key } from "../../../types/collections"; | ||||
| import { isDefined } from "../../../utils/asserts"; | ||||
| import { CollectionEndpoint, PayloadCreateData } from "../../../types/payload"; | ||||
| import { StrapiLanguage } from "../../../types/strapi"; | ||||
| import { isDefined, isUndefined } from "../../../utils/asserts"; | ||||
| import { formatToCamelCase } from "../../../utils/string"; | ||||
| import { PayloadCreateData } from "../../../utils/types"; | ||||
| 
 | ||||
| const importStrapiWordings: typeof importStrapiEntries = async ({ | ||||
|   payload: payloadParams, | ||||
| @ -30,7 +30,7 @@ const importStrapiWordings: typeof importStrapiEntries = async ({ | ||||
|       .filter(({ name }) => isDefined(name) && name !== ""), | ||||
|   })); | ||||
| 
 | ||||
|   const errors = []; | ||||
|   const errors: string[] = []; | ||||
| 
 | ||||
|   await Promise.all( | ||||
|     entries.map(async (entry) => { | ||||
| @ -42,7 +42,9 @@ const importStrapiWordings: typeof importStrapiEntries = async ({ | ||||
|         }); | ||||
|       } catch (e) { | ||||
|         console.warn(e); | ||||
|         errors.push(`${e.name} with ${entry.name}`); | ||||
|         if (typeof e === "object" && isDefined(e) && "name" in e) { | ||||
|           errors.push(`${e.name} with ${entry.name}`); | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
|   ); | ||||
| @ -50,7 +52,7 @@ const importStrapiWordings: typeof importStrapiEntries = async ({ | ||||
|   return { count: entries.length, errors }; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi: CollectionConfig["endpoints"][number] = { | ||||
| export const importFromStrapi: CollectionEndpoint = { | ||||
|   method: "get", | ||||
|   path: "/strapi", | ||||
|   handler: async (req, res) => { | ||||
| @ -64,7 +66,15 @@ export const importFromStrapi: CollectionConfig["endpoints"][number] = { | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     const { count: categoriesCount, errors: categoriesErrors } = await importStrapiEntries<Key>({ | ||||
|     type StrapiCategories = { | ||||
|       slug: string; | ||||
|       titles: { title?: string; short?: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: categoriesCount, errors: categoriesErrors } = await importStrapiEntries< | ||||
|       Key, | ||||
|       StrapiCategories | ||||
|     >({ | ||||
|       strapi: { | ||||
|         collection: "categories", | ||||
|         params: { populate: { titles: { populate: "language" } } }, | ||||
| @ -74,59 +84,96 @@ export const importFromStrapi: CollectionConfig["endpoints"][number] = { | ||||
|         convert: ({ slug, titles }) => ({ | ||||
|           name: slug, | ||||
|           type: "Categories", | ||||
|           translations: titles.map(({ title, short, language }) => ({ | ||||
|             name: title, | ||||
|             short, | ||||
|             language: language.data.attributes.code, | ||||
|           })), | ||||
|           translations: titles.map(({ title, short, language }) => { | ||||
|             if (isUndefined(language.data)) | ||||
|               throw new Error("A language is required for a Keys title translation"); | ||||
|             if (isUndefined(title)) | ||||
|               throw new Error("A title is required for a Keys title translation"); | ||||
|             return { | ||||
|               name: title, | ||||
|               short, | ||||
|               language: language.data.attributes.code, | ||||
|             }; | ||||
|           }), | ||||
|         }), | ||||
|       }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     const { count: contentTypesCount, errors: contentTypesErrors } = await importStrapiEntries<Key>( | ||||
|       { | ||||
|         strapi: { | ||||
|           collection: "content-types", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "Contents", | ||||
|             translations: titles.map(({ title, language }) => ({ | ||||
|     type StrapiContentType = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: contentTypesCount, errors: contentTypesErrors } = await importStrapiEntries< | ||||
|       Key, | ||||
|       StrapiContentType | ||||
|     >({ | ||||
|       strapi: { | ||||
|         collection: "content-types", | ||||
|         params: { populate: { titles: { populate: "language" } } }, | ||||
|       }, | ||||
|       payload: { | ||||
|         collection: Collections.Keys, | ||||
|         convert: ({ slug, titles }) => ({ | ||||
|           name: slug, | ||||
|           type: "Contents", | ||||
|           translations: titles.map(({ title, language }) => { | ||||
|             if (isUndefined(language.data)) | ||||
|               throw new Error("A language is required for a Keys title translation"); | ||||
|             return { | ||||
|               name: title, | ||||
|               language: language.data.attributes.code, | ||||
|             })), | ||||
|             }; | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       } | ||||
|     ); | ||||
|         }), | ||||
|       }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     const { count: gamePlatformsCount, errors: gamePlatformsErrors } = | ||||
|       await importStrapiEntries<Key>({ | ||||
|         strapi: { | ||||
|           collection: "game-platforms", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "GamePlatforms", | ||||
|             translations: titles.map(({ title, short, language }) => ({ | ||||
|     type StrapiGamePlatform = { | ||||
|       slug: string; | ||||
|       titles: { title?: string; short?: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: gamePlatformsCount, errors: gamePlatformsErrors } = await importStrapiEntries< | ||||
|       Key, | ||||
|       StrapiGamePlatform | ||||
|     >({ | ||||
|       strapi: { | ||||
|         collection: "game-platforms", | ||||
|         params: { populate: { titles: { populate: "language" } } }, | ||||
|       }, | ||||
|       payload: { | ||||
|         collection: Collections.Keys, | ||||
|         convert: ({ slug, titles }) => ({ | ||||
|           name: slug, | ||||
|           type: "GamePlatforms", | ||||
|           translations: titles.map(({ title, short, language }) => { | ||||
|             if (isUndefined(language.data)) | ||||
|               throw new Error("A language is required for a Keys title translation"); | ||||
|             if (isUndefined(title)) | ||||
|               throw new Error("A title is required for a Keys title translation"); | ||||
|             return { | ||||
|               name: title, | ||||
|               short, | ||||
|               language: language.data.attributes.code, | ||||
|             })), | ||||
|             }; | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
|         }), | ||||
|       }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     const { count: libraryCount, errors: libraryErrors } = await importStrapiEntries<Key>({ | ||||
|     type StrapiMetadataTypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryCount, errors: libraryErrors } = await importStrapiEntries< | ||||
|       Key, | ||||
|       StrapiMetadataTypes | ||||
|     >({ | ||||
|       strapi: { | ||||
|         collection: "metadata-types", | ||||
|         params: { populate: { titles: { populate: "language" } } }, | ||||
| @ -136,99 +183,152 @@ export const importFromStrapi: CollectionConfig["endpoints"][number] = { | ||||
|         convert: ({ slug, titles }) => ({ | ||||
|           name: slug, | ||||
|           type: "Library", | ||||
|           translations: titles.map(({ title, language }) => ({ | ||||
|             name: title, | ||||
|             language: language.data.attributes.code, | ||||
|           })), | ||||
|           translations: titles.map(({ title, language }) => { | ||||
|             if (isUndefined(language.data)) | ||||
|               throw new Error("A language is required for a Keys title translation"); | ||||
|             return { | ||||
|               name: title, | ||||
|               language: language.data.attributes.code, | ||||
|             }; | ||||
|           }), | ||||
|         }), | ||||
|       }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     const { count: libraryAudioCount, errors: libraryAudioErrors } = await importStrapiEntries<Key>( | ||||
|       { | ||||
|         strapi: { | ||||
|           collection: "audio-subtypes", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "LibraryAudio", | ||||
|             translations: titles.map(({ title, language }) => ({ | ||||
|     type StrapiAudioSubtypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryAudioCount, errors: libraryAudioErrors } = await importStrapiEntries< | ||||
|       Key, | ||||
|       StrapiAudioSubtypes | ||||
|     >({ | ||||
|       strapi: { | ||||
|         collection: "audio-subtypes", | ||||
|         params: { populate: { titles: { populate: "language" } } }, | ||||
|       }, | ||||
|       payload: { | ||||
|         collection: Collections.Keys, | ||||
|         convert: ({ slug, titles }) => ({ | ||||
|           name: slug, | ||||
|           type: "LibraryAudio", | ||||
|           translations: titles.map(({ title, language }) => { | ||||
|             if (isUndefined(language.data)) | ||||
|               throw new Error("A language is required for a Keys title translation"); | ||||
|             return { | ||||
|               name: title, | ||||
|               language: language.data.attributes.code, | ||||
|             })), | ||||
|             }; | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       } | ||||
|     ); | ||||
|         }), | ||||
|       }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     const { count: libraryGroupCount, errors: libraryGroupErrors } = await importStrapiEntries<Key>( | ||||
|       { | ||||
|         strapi: { | ||||
|           collection: "group-subtypes", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "LibraryGroup", | ||||
|             translations: titles.map(({ title, language }) => ({ | ||||
|     type StrapiGroupSubtypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryGroupCount, errors: libraryGroupErrors } = await importStrapiEntries< | ||||
|       Key, | ||||
|       StrapiGroupSubtypes | ||||
|     >({ | ||||
|       strapi: { | ||||
|         collection: "group-subtypes", | ||||
|         params: { populate: { titles: { populate: "language" } } }, | ||||
|       }, | ||||
|       payload: { | ||||
|         collection: Collections.Keys, | ||||
|         convert: ({ slug, titles }) => ({ | ||||
|           name: slug, | ||||
|           type: "LibraryGroup", | ||||
|           translations: titles.map(({ title, language }) => { | ||||
|             if (isUndefined(language.data)) | ||||
|               throw new Error("A language is required for a Keys title translation"); | ||||
|             return { | ||||
|               name: title, | ||||
|               language: language.data.attributes.code, | ||||
|             })), | ||||
|             }; | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       } | ||||
|     ); | ||||
|         }), | ||||
|       }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     const { count: libraryTextualCount, errors: libraryTextualErrors } = | ||||
|       await importStrapiEntries<Key>({ | ||||
|         strapi: { | ||||
|           collection: "textual-subtypes", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "LibraryTextual", | ||||
|             translations: titles.map(({ title, language }) => ({ | ||||
|     type StrapiTextualSubtypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryTextualCount, errors: libraryTextualErrors } = await importStrapiEntries< | ||||
|       Key, | ||||
|       StrapiTextualSubtypes | ||||
|     >({ | ||||
|       strapi: { | ||||
|         collection: "textual-subtypes", | ||||
|         params: { populate: { titles: { populate: "language" } } }, | ||||
|       }, | ||||
|       payload: { | ||||
|         collection: Collections.Keys, | ||||
|         convert: ({ slug, titles }) => ({ | ||||
|           name: slug, | ||||
|           type: "LibraryTextual", | ||||
|           translations: titles.map(({ title, language }) => { | ||||
|             if (isUndefined(language.data)) | ||||
|               throw new Error("A language is required for a Keys title translation"); | ||||
|             return { | ||||
|               name: title, | ||||
|               language: language.data.attributes.code, | ||||
|             })), | ||||
|             }; | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
|         }), | ||||
|       }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     const { count: libraryVideoCount, errors: libraryVideoErrors } = await importStrapiEntries<Key>( | ||||
|       { | ||||
|         strapi: { | ||||
|           collection: "video-subtypes", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "LibraryVideo", | ||||
|             translations: titles.map(({ title, language }) => ({ | ||||
|     type StrapiVideoSubtypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryVideoCount, errors: libraryVideoErrors } = await importStrapiEntries< | ||||
|       Key, | ||||
|       StrapiVideoSubtypes | ||||
|     >({ | ||||
|       strapi: { | ||||
|         collection: "video-subtypes", | ||||
|         params: { populate: { titles: { populate: "language" } } }, | ||||
|       }, | ||||
|       payload: { | ||||
|         collection: Collections.Keys, | ||||
|         convert: ({ slug, titles }) => ({ | ||||
|           name: slug, | ||||
|           type: "LibraryVideo", | ||||
|           translations: titles.map(({ title, language }) => { | ||||
|             if (isUndefined(language.data)) | ||||
|               throw new Error("A language is required for a Keys title translation"); | ||||
|             return { | ||||
|               name: title, | ||||
|               language: language.data.attributes.code, | ||||
|             })), | ||||
|             }; | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       } | ||||
|     ); | ||||
|         }), | ||||
|       }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     const { count: weaponsCount, errors: weaponsErrors } = await importStrapiEntries<Key>({ | ||||
|     type StrapiWeaponTypes = { | ||||
|       slug: string; | ||||
|       translations: { name?: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: weaponsCount, errors: weaponsErrors } = await importStrapiEntries< | ||||
|       Key, | ||||
|       StrapiWeaponTypes | ||||
|     >({ | ||||
|       strapi: { | ||||
|         collection: "weapon-story-types", | ||||
|         params: { populate: { translations: { populate: "language" } } }, | ||||
| @ -238,16 +338,22 @@ export const importFromStrapi: CollectionConfig["endpoints"][number] = { | ||||
|         convert: ({ slug, translations }) => ({ | ||||
|           name: slug, | ||||
|           type: "Weapons", | ||||
|           translations: translations.map(({ name, language }) => ({ | ||||
|             name, | ||||
|             language: language.data.attributes.code, | ||||
|           })), | ||||
|           translations: translations.map(({ name, language }) => { | ||||
|             if (isUndefined(language.data)) | ||||
|               throw new Error("A language is required for a Keys title translation"); | ||||
|             if (isUndefined(name)) | ||||
|               throw new Error("A name is required for a Keys title translation"); | ||||
|             return { | ||||
|               name, | ||||
|               language: language.data.attributes.code, | ||||
|             }; | ||||
|           }), | ||||
|         }), | ||||
|       }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     const { count: wordingsCount, errors: wordingsErrors } = await importStrapiWordings({ | ||||
|     const { count: wordingsCount, errors: wordingsErrors } = await importStrapiWordings<Key, Key>({ | ||||
|       strapi: { collection: "website-interfaces", params: { populate: "ui_language" } }, | ||||
|       payload: { collection: Collections.Keys, convert: (strapiObject) => strapiObject }, | ||||
|       user: req.user, | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { text } from "payload/dist/fields/validations"; | ||||
| import { mustBeAdmin } from "../../accesses/mustBeAdmin"; | ||||
| import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { publicAccess } from "../../accesses/publicAccess"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
|  | ||||
| @ -2,7 +2,12 @@ import { Collections } from "../../../constants"; | ||||
| import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { Language } from "../../../types/collections"; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Language>({ | ||||
| type StrapiLanguage = { | ||||
|   name: string; | ||||
|   code: string; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Language, StrapiLanguage>({ | ||||
|   strapi: { | ||||
|     collection: "languages", | ||||
|     params: {}, | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types"; | ||||
| import { | ||||
|   CollectionGroups, | ||||
|   Collections, | ||||
| @ -18,7 +19,6 @@ import { LibraryItem } from "../../types/collections"; | ||||
| import { isDefined } from "../../utils/asserts"; | ||||
| import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; | ||||
| import { RowLabel } from "./components/RowLabel"; | ||||
| import { getBySlug } from "./endpoints/getBySlug"; | ||||
| 
 | ||||
| const fields = { | ||||
|   status: "_status", | ||||
| @ -139,7 +139,6 @@ export const LibraryItems = buildVersionedCollectionConfig({ | ||||
|     }, | ||||
|     preview: (doc) => `https://accords-library.com/library/${doc.slug}`, | ||||
|   }, | ||||
|   endpoints: [getBySlug], | ||||
|   fields: [ | ||||
|     { | ||||
|       name: fields.itemType, | ||||
| @ -480,7 +479,7 @@ export const LibraryItems = buildVersionedCollectionConfig({ | ||||
|                       "Make sure the page number corresponds to the page number written on \ | ||||
|                   the scan. You can use negative page numbers if necessary.", | ||||
|                     components: { | ||||
|                       RowLabel: ({ data }) => RowLabel(data), | ||||
|                       RowLabel: ({ data }: RowLabelArgs) => RowLabel(data), | ||||
|                     }, | ||||
|                   }, | ||||
|                   fields: [ | ||||
|  | ||||
| @ -1,59 +0,0 @@ | ||||
| import cleanDeep from "clean-deep"; | ||||
| import { Collections } from "../../../constants"; | ||||
| import { createGetByEndpoint } from "../../../endpoints/createByEndpoint"; | ||||
| import { LibraryItem } from "../../../types/collections"; | ||||
| 
 | ||||
| type ProcessedLibraryItem = Omit<LibraryItem, "size" | "price" | "scans" | "id"> & { | ||||
|   size?: Omit<LibraryItem["size"][number], "id">; | ||||
|   price?: Omit<LibraryItem["price"][number], "id" | "currency"> & { currency: string }; | ||||
|   scans?: Omit<LibraryItem["scans"][number], "id" | "obi" | "cover" | "dustjacket"> & { | ||||
|     obi: Omit<LibraryItem["scans"][number]["obi"][number], "id">; | ||||
|     cover: Omit<LibraryItem["scans"][number]["obi"][number], "id">; | ||||
|     dustjacket: Omit<LibraryItem["scans"][number]["obi"][number], "id">; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| export const getBySlug = createGetByEndpoint<LibraryItem, Partial<ProcessedLibraryItem>>( | ||||
|   Collections.LibraryItems, | ||||
|   "slug", | ||||
|   async ({ id, size, price, scans, ...otherProps }) => { | ||||
|     const processedLibraryItem: ProcessedLibraryItem = { | ||||
|       size: processOptionalGroup(size), | ||||
|       price: processPrice(price), | ||||
|       scans: processScans(scans), | ||||
|       ...otherProps, | ||||
|     }; | ||||
| 
 | ||||
|     return cleanDeep(processedLibraryItem, { | ||||
|       emptyStrings: false, | ||||
|       emptyArrays: false, | ||||
|       emptyObjects: false, | ||||
|       nullValues: true, | ||||
|       undefinedValues: true, | ||||
|       NaNValues: false, | ||||
|     }); | ||||
|   } | ||||
| ); | ||||
| 
 | ||||
| const processScans = (scans: LibraryItem["scans"]): ProcessedLibraryItem["scans"] => { | ||||
|   if (!scans || scans.length === 0) return undefined; | ||||
|   const { cover, dustjacket, id, obi, ...otherProps } = scans[0]; | ||||
|   return { | ||||
|     cover: processOptionalGroup(cover), | ||||
|     dustjacket: processOptionalGroup(dustjacket), | ||||
|     obi: processOptionalGroup(obi), | ||||
|     ...otherProps, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const processPrice = (price: LibraryItem["price"]): ProcessedLibraryItem["price"] => { | ||||
|   if (!price || price.length === 0) return undefined; | ||||
|   const { currency, ...otherProps } = processOptionalGroup(price); | ||||
|   return { ...otherProps, currency: typeof currency === "string" ? currency : currency.id }; | ||||
| }; | ||||
| 
 | ||||
| const processOptionalGroup = <T extends { id?: string }>(group: T[] | null | undefined) => { | ||||
|   if (!group || group.length === 0) return undefined; | ||||
|   const { id, ...otherProps } = group[0]; | ||||
|   return otherProps; | ||||
| }; | ||||
| @ -8,7 +8,6 @@ import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping"; | ||||
| import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish"; | ||||
| import { isDefined, isUndefined } from "../../utils/asserts"; | ||||
| import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; | ||||
| import { removeTranslatorsForTranscripts } from "./hooks/beforeValidate"; | ||||
| 
 | ||||
| const fields = { | ||||
|   slug: "slug", | ||||
| @ -57,9 +56,6 @@ export const Posts = buildVersionedCollectionConfig({ | ||||
|     }, | ||||
|     preview: (doc) => `https://accords-library.com/news/${doc.slug}`, | ||||
|   }, | ||||
|   hooks: { | ||||
|     beforeValidate: [removeTranslatorsForTranscripts], | ||||
|   }, | ||||
|   fields: [ | ||||
|     { | ||||
|       type: "row", | ||||
| @ -110,6 +106,15 @@ export const Posts = buildVersionedCollectionConfig({ | ||||
|               type: "relationship", | ||||
|               relationTo: Collections.Recorders, | ||||
|               hasMany: true, | ||||
|               hooks: { | ||||
|                 beforeChange: [ | ||||
|                   ({ siblingData }) => { | ||||
|                     if (siblingData.language === siblingData.sourceLanguage) { | ||||
|                       delete siblingData.translators; | ||||
|                     } | ||||
|                   }, | ||||
|                 ], | ||||
|               }, | ||||
|               admin: { | ||||
|                 condition: (_, siblingData) => { | ||||
|                   if ( | ||||
|  | ||||
| @ -1,14 +0,0 @@ | ||||
| import { CollectionBeforeValidateHook } from "payload/types"; | ||||
| import { Post } from "../../../types/collections"; | ||||
| 
 | ||||
| export const removeTranslatorsForTranscripts: CollectionBeforeValidateHook<Post> = async ({ | ||||
|   data: { translations, ...data }, | ||||
| }) => ({ | ||||
|   ...data, | ||||
|   translations: translations?.map(({ translators, ...translation }) => { | ||||
|     if (translation.language === translation.sourceLanguage) { | ||||
|       return { ...translation, translators: [] }; | ||||
|     } | ||||
|     return { ...translation, translators }; | ||||
|   }), | ||||
| }); | ||||
| @ -1,5 +1,6 @@ | ||||
| import { mustBeAdmin as mustBeAdminForCollections } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { mustBeAdminOrSelf } from "../../accesses/collections/mustBeAdminOrSelf"; | ||||
| import { mustBeAdmin } from "../../accesses/mustBeAdmin"; | ||||
| import { mustBeAdmin as mustBeAdminForFields } from "../../accesses/fields/mustBeAdmin"; | ||||
| import { QuickFilters } from "../../components/QuickFilters"; | ||||
| import { CollectionGroups, Collections, RecordersRoles } from "../../constants"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| @ -55,7 +56,6 @@ export const Recorders = buildCollectionConfig({ | ||||
|                   label: "∅ Role", | ||||
|                   filter: { where: { role: { not_in: Object.keys(RecordersRoles).join(",") } } }, | ||||
|                 }, | ||||
|                 , | ||||
|               ], | ||||
|               [{ label: "Anonymized", filter: { where: { anonymize: { equals: true } } } }], | ||||
|             ], | ||||
| @ -65,10 +65,10 @@ export const Recorders = buildCollectionConfig({ | ||||
|   }, | ||||
|   auth: true, | ||||
|   access: { | ||||
|     unlock: mustBeAdmin, | ||||
|     unlock: mustBeAdminForCollections, | ||||
|     update: mustBeAdminOrSelf, | ||||
|     delete: mustBeAdmin, | ||||
|     create: mustBeAdmin, | ||||
|     delete: mustBeAdminForCollections, | ||||
|     create: mustBeAdminForCollections, | ||||
|   }, | ||||
|   hooks: { | ||||
|     beforeLogin: [beforeLoginMustHaveAtLeastOneRole], | ||||
| @ -111,14 +111,14 @@ export const Recorders = buildCollectionConfig({ | ||||
|         description: | ||||
|           "A short personal description about you or your involvement with this project or the franchise", | ||||
|       }, | ||||
|       fields: [{ name: fields.biography, type: "textarea" }], | ||||
|       fields: [{ name: fields.biography, required: true, type: "textarea" }], | ||||
|     }), | ||||
|     { | ||||
|       name: fields.role, | ||||
|       type: "select", | ||||
|       access: { | ||||
|         update: mustBeAdmin, | ||||
|         create: mustBeAdmin, | ||||
|         update: mustBeAdminForFields, | ||||
|         create: mustBeAdminForFields, | ||||
|       }, | ||||
|       hasMany: true, | ||||
|       options: Object.entries(RecordersRoles).map(([value, label]) => ({ | ||||
|  | ||||
| @ -2,10 +2,21 @@ import payload from "payload"; | ||||
| import { Collections } from "../../../constants"; | ||||
| import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { Recorder } from "../../../types/collections"; | ||||
| import { PayloadCreateData } from "../../../types/payload"; | ||||
| import { StrapiImage, StrapiLanguage } from "../../../types/strapi"; | ||||
| import { isUndefined } from "../../../utils/asserts"; | ||||
| import { uploadStrapiImage } from "../../../utils/localApi"; | ||||
| import { PayloadCreateData } from "../../../utils/types"; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Recorder>({ | ||||
| type StrapiRecorder = { | ||||
|   username: string; | ||||
|   anonymize: boolean; | ||||
|   anonymous_code: number; | ||||
|   languages: { data: { attributes: { code: string } }[] }; | ||||
|   avatar: StrapiImage; | ||||
|   bio: { language: StrapiLanguage; bio?: string }[]; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Recorder, StrapiRecorder>({ | ||||
|   strapi: { | ||||
|     collection: "recorders", | ||||
|     params: { | ||||
| @ -27,10 +38,15 @@ export const importFromStrapi = createStrapiImportEndpoint<Recorder>({ | ||||
|         anonymize, | ||||
|         languages: languages.data?.map((language) => language.attributes.code), | ||||
|         avatar: avatarId, | ||||
|         biographies: bios?.map(({ language, bio }) => ({ | ||||
|           language: language.data.attributes.code, | ||||
|           biography: bio, | ||||
|         })), | ||||
|         biographies: bios?.map(({ language, bio }) => { | ||||
|           if (isUndefined(language.data)) | ||||
|             throw new Error("A language is required for a Recorder biography"); | ||||
|           if (isUndefined(bio)) throw new Error("A bio is required for a Recorder biography"); | ||||
|           return { | ||||
|             language: language.data.attributes.code, | ||||
|             biography: bio, | ||||
|           }; | ||||
|         }), | ||||
|       }; | ||||
| 
 | ||||
|       await payload.create({ collection: Collections.Recorders, data, user }); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { mustBeAdmin } from "../../accesses/mustBeAdmin"; | ||||
| import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { CollectionGroups, Collections, VideoSources } from "../../constants"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { importFromStrapi } from "./endpoints/importFromStrapi"; | ||||
|  | ||||
| @ -2,9 +2,26 @@ import payload from "payload"; | ||||
| import { Collections } from "../../../constants"; | ||||
| import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { Video, VideosChannel } from "../../../types/collections"; | ||||
| import { PayloadCreateData } from "../../../utils/types"; | ||||
| import { PayloadCreateData } from "../../../types/payload"; | ||||
| import { isUndefined } from "../../../utils/asserts"; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Video>({ | ||||
| type StapiVideo = { | ||||
|   uid: string; | ||||
|   title: string; | ||||
|   description: string; | ||||
|   published_date: { | ||||
|     year?: number; | ||||
|     month?: number; | ||||
|     day?: number; | ||||
|   }; | ||||
|   views: number; | ||||
|   likes: number; | ||||
|   source?: "YouTube" | "NicoNico" | "Tumblr"; | ||||
|   gone: boolean; | ||||
|   channel: { data?: { attributes: { uid: string; title: string; subscribers: number } } }; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Video, StapiVideo>({ | ||||
|   strapi: { | ||||
|     collection: "videos", | ||||
|     params: { populate: "published_date,channel" }, | ||||
| @ -25,6 +42,9 @@ export const importFromStrapi = createStrapiImportEndpoint<Video>({ | ||||
|       }, | ||||
|       user | ||||
|     ) => { | ||||
|       if (isUndefined(source)) throw new Error("A source is required to create a Video"); | ||||
|       if (isUndefined(channel.data)) throw new Error("A channel is required to create a Video"); | ||||
| 
 | ||||
|       try { | ||||
|         const videoChannel: PayloadCreateData<VideosChannel> = { | ||||
|           uid: channel.data.attributes.uid, | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { mustBeAdmin } from "../../accesses/mustBeAdmin"; | ||||
| import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { importFromStrapi } from "./endpoints/importFromStrapi"; | ||||
|  | ||||
| @ -2,7 +2,13 @@ import { Collections } from "../../../constants"; | ||||
| import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { VideosChannel } from "../../../types/collections"; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<VideosChannel>({ | ||||
| type StrapiVideoChannel = { | ||||
|   uid: string; | ||||
|   title: string; | ||||
|   subscribers: number; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<VideosChannel, StrapiVideoChannel>({ | ||||
|   strapi: { | ||||
|     collection: "video-channels", | ||||
|     params: {}, | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types"; | ||||
| import { CollectionGroups, Collections, KeysTypes } from "../../constants"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| import { keysField } from "../../fields/keysField/keysField"; | ||||
| @ -78,7 +79,7 @@ export const Weapons = buildVersionedCollectionConfig({ | ||||
|       admin: { | ||||
|         initCollapsed: true, | ||||
|         components: { | ||||
|           RowLabel: ({ data }) => | ||||
|           RowLabel: ({ data }: RowLabelArgs) => | ||||
|             AppearanceRowLabel({ keyIds: data[fields.appearancesCategories] ?? [] }), | ||||
|         }, | ||||
|       }, | ||||
|  | ||||
| @ -2,11 +2,31 @@ import payload from "payload"; | ||||
| import { Collections } from "../../../constants"; | ||||
| import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { Weapon, WeaponsGroup } from "../../../types/collections"; | ||||
| import { isDefined } from "../../../utils/asserts"; | ||||
| import { PayloadCreateData } from "../../../types/payload"; | ||||
| import { StrapiImage, StrapiLanguage } from "../../../types/strapi"; | ||||
| import { isDefined, isUndefined } from "../../../utils/asserts"; | ||||
| import { findCategory, findWeaponType, uploadStrapiImage } from "../../../utils/localApi"; | ||||
| import { PayloadCreateData } from "../../../utils/types"; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Weapon>({ | ||||
| type StrapiWeapon = { | ||||
|   slug: string; | ||||
|   name: { name: string; language: StrapiLanguage }[]; | ||||
|   weapon_group: { data?: { attributes: { slug: string } } }; | ||||
|   thumbnail: StrapiImage; | ||||
|   type: { data?: { attributes: { slug: string } } }; | ||||
|   stories: { | ||||
|     categories: { data: { attributes: { slug: string } }[] }; | ||||
|     translations: { | ||||
|       language: StrapiLanguage; | ||||
|       description?: string; | ||||
|       level_1?: string; | ||||
|       level_2?: string; | ||||
|       level_3?: string; | ||||
|       level_4?: string; | ||||
|     }[]; | ||||
|   }[]; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi = createStrapiImportEndpoint<Weapon, StrapiWeapon>({ | ||||
|   strapi: { | ||||
|     collection: "weapon-stories", | ||||
|     params: { | ||||
| @ -23,7 +43,7 @@ export const importFromStrapi = createStrapiImportEndpoint<Weapon>({ | ||||
|   payload: { | ||||
|     collection: Collections.Weapons, | ||||
|     import: async ({ slug, type, stories, name: names, weapon_group, thumbnail }, user) => { | ||||
|       let groupId: string; | ||||
|       let groupId: string | undefined; | ||||
|       if (isDefined(weapon_group.data)) { | ||||
|         try { | ||||
|           const groupData: PayloadCreateData<WeaponsGroup> = { | ||||
| @ -51,6 +71,8 @@ export const importFromStrapi = createStrapiImportEndpoint<Weapon>({ | ||||
|         image: thumbnail, | ||||
|       }); | ||||
| 
 | ||||
|       if (isUndefined(type.data)) throw new Error("A type is required to create a Weapon"); | ||||
| 
 | ||||
|       const data: PayloadCreateData<Weapon> = { | ||||
|         slug, | ||||
|         type: await findWeaponType(type.data.attributes.slug), | ||||
| @ -62,19 +84,26 @@ export const importFromStrapi = createStrapiImportEndpoint<Weapon>({ | ||||
|               categories.data.map(({ attributes }) => findCategory(attributes.slug)) | ||||
|             ), | ||||
|             translations: translations.map( | ||||
|               ({ language, description, level_1, level_2, level_3, level_4 }) => ({ | ||||
|                 language: language.data?.attributes.code, | ||||
|                 sourceLanguage: language.data?.attributes.code, | ||||
|                 name: names.find( | ||||
|               ({ language, description, level_1, level_2, level_3, level_4 }) => { | ||||
|                 if (isUndefined(language.data)) | ||||
|                   throw new Error("A language is required to create a Weapon translation"); | ||||
|                 const name = names.find( | ||||
|                   (name) => name.language.data?.attributes.code === language.data?.attributes.code | ||||
|                 )?.name, | ||||
|                 description, | ||||
|                 level1: level_1, | ||||
|                 level2: level_2, | ||||
|                 level3: level_3, | ||||
|                 level4: level_4, | ||||
|                 transcribers: [user.id], | ||||
|               }) | ||||
|                 )?.name; | ||||
|                 if (isUndefined(name)) | ||||
|                   throw new Error("A name is required to create a Weapon translation"); | ||||
|                 return { | ||||
|                   language: language.data?.attributes.code, | ||||
|                   sourceLanguage: language.data?.attributes.code, | ||||
|                   name, | ||||
|                   description, | ||||
|                   level1: level_1, | ||||
|                   level2: level_2, | ||||
|                   level3: level_3, | ||||
|                   level4: level_4, | ||||
|                   transcribers: [user.id], | ||||
|                 }; | ||||
|               } | ||||
|             ), | ||||
|           })) | ||||
|         ), | ||||
|  | ||||
| @ -1,11 +1,11 @@ | ||||
| import payload from "payload"; | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { CollectionEndpoint } from "../types/payload"; | ||||
| 
 | ||||
| export const createGetByEndpoint = <T, R>( | ||||
|   collection: string, | ||||
|   attribute: string, | ||||
|   handler: (doc: T) => Promise<R> | ||||
| ): CollectionConfig["endpoints"][number] => ({ | ||||
| ): CollectionEndpoint => ({ | ||||
|   path: `/${attribute}/:${attribute}`, | ||||
|   method: "get", | ||||
|   handler: async (req, res) => { | ||||
|  | ||||
| @ -1,9 +1,8 @@ | ||||
| import payload from "payload"; | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import QueryString from "qs"; | ||||
| import { Recorder } from "../types/collections"; | ||||
| import { CollectionEndpoint, PayloadCreateData } from "../types/payload"; | ||||
| import { isDefined } from "../utils/asserts"; | ||||
| import { PayloadCreateData } from "../utils/types"; | ||||
| 
 | ||||
| export const getAllStrapiEntries = async <T>( | ||||
|   collectionSlug: string, | ||||
| @ -31,26 +30,26 @@ export const getAllStrapiEntries = async <T>( | ||||
|   return result; | ||||
| }; | ||||
| 
 | ||||
| type Params<T> = { | ||||
| type Params<T, S> = { | ||||
|   strapi: { | ||||
|     collection: string; | ||||
|     params: any; | ||||
|   }; | ||||
|   payload: { | ||||
|     collection: string; | ||||
|     import?: (strapiObject: any, user: any) => Promise<void>; | ||||
|     convert?: (strapiObject: any, user: any) => PayloadCreateData<T>; | ||||
|     import?: (strapiObject: S, user: any) => Promise<void>; | ||||
|     convert?: (strapiObject: S, user: any) => PayloadCreateData<T>; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| export const importStrapiEntries = async <T>({ | ||||
| export const importStrapiEntries = async <T, S>({ | ||||
|   strapi: strapiParams, | ||||
|   payload: payloadParams, | ||||
|   user, | ||||
| }: Params<T> & { user: Recorder }) => { | ||||
| }: Params<T, S> & { user: Recorder }) => { | ||||
|   const entries = await getAllStrapiEntries<any>(strapiParams.collection, strapiParams.params); | ||||
| 
 | ||||
|   const errors = []; | ||||
|   const errors: string[] = []; | ||||
| 
 | ||||
|   await Promise.all( | ||||
|     entries.map(async ({ attributes, id }) => { | ||||
| @ -68,7 +67,9 @@ export const importStrapiEntries = async <T>({ | ||||
|         } | ||||
|       } catch (e) { | ||||
|         console.warn(e); | ||||
|         errors.push(`${e.name} with ${id}`); | ||||
|         if (typeof e === "object" && isDefined(e) && "name" in e) { | ||||
|           errors.push(`${e.name} with ${id}`); | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
|   ); | ||||
| @ -76,9 +77,7 @@ export const importStrapiEntries = async <T>({ | ||||
|   return { count: entries.length, errors }; | ||||
| }; | ||||
| 
 | ||||
| export const createStrapiImportEndpoint = <T>( | ||||
|   params: Params<T> | ||||
| ): CollectionConfig["endpoints"][number] => ({ | ||||
| export const createStrapiImportEndpoint = <T, S>(params: Params<T, S>): CollectionEndpoint => ({ | ||||
|   method: "get", | ||||
|   path: "/strapi", | ||||
|   handler: async (req, res) => { | ||||
|  | ||||
| @ -30,7 +30,7 @@ export const backPropagationField = ({ | ||||
|     afterRead: [ | ||||
|       ...afterRead, | ||||
|       async ({ data }) => { | ||||
|         if (isNotEmpty(data.id)) { | ||||
|         if (isNotEmpty(data?.id)) { | ||||
|           const result = await payload.find({ | ||||
|             collection: params.relationTo, | ||||
|             where: where(data), | ||||
|  | ||||
| @ -19,5 +19,5 @@ export const keysField = ({ | ||||
|   filterOptions: { type: { equals: getKeysTypesKey(relationTo) } }, | ||||
| }); | ||||
| 
 | ||||
| const getKeysTypesKey = (keyType: KeysTypes): string => | ||||
|   Object.entries(KeysTypes).find(([, value]) => value === keyType)[0]; | ||||
| const getKeysTypesKey = (keyType: KeysTypes): string | undefined => | ||||
|   Object.entries(KeysTypes).find(([, value]) => value === keyType)?.[0]; | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types"; | ||||
| import { array } from "payload/dist/fields/validations"; | ||||
| import { ArrayField, Field } from "payload/types"; | ||||
| import { Collections } from "../../constants"; | ||||
| @ -118,6 +119,8 @@ const creditFields: Field = { | ||||
|   ], | ||||
| }; | ||||
| 
 | ||||
| type FieldData = Record<string, any> & { [fieldsNames.language]: string }; | ||||
| 
 | ||||
| export const translatedFields = ({ | ||||
|   fields, | ||||
|   validate, | ||||
| @ -129,7 +132,7 @@ export const translatedFields = ({ | ||||
|   admin: { | ||||
|     initCollapsed: true, | ||||
|     components: { | ||||
|       Cell: ({ cellData }) => | ||||
|       Cell: ({ cellData }: { cellData: FieldData[] }) => | ||||
|         Cell({ | ||||
|           cellData: | ||||
|             cellData?.map((row) => ({ | ||||
| @ -137,7 +140,7 @@ export const translatedFields = ({ | ||||
|               title: isDefined(useAsTitle) ? row[useAsTitle] : undefined, | ||||
|             })) ?? [], | ||||
|         }), | ||||
|       RowLabel: ({ data }) => | ||||
|       RowLabel: ({ data }: RowLabelArgs) => | ||||
|         RowLabel({ | ||||
|           language: data[fieldsNames.language], | ||||
|           title: isDefined(useAsTitle) ? data[useAsTitle] : undefined, | ||||
| @ -162,6 +165,8 @@ export const translatedFields = ({ | ||||
|     if (hasDuplicates(languages)) { | ||||
|       return `There cannot be multiple ${otherProps.name} with the same ${fieldsNames.language}`; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
|   }, | ||||
|   fields: [ | ||||
|     hasSourceLanguage | ||||
|  | ||||
| @ -4,7 +4,8 @@ import path from "path"; | ||||
| import payload from "payload"; | ||||
| import { Collections, RecordersRoles } from "./constants"; | ||||
| import { Recorder } from "./types/collections"; | ||||
| import { PayloadCreateData } from "./utils/types"; | ||||
| import { PayloadCreateData } from "./types/payload"; | ||||
| import { isDefined, isUndefined } from "./utils/asserts"; | ||||
| 
 | ||||
| const app = express(); | ||||
| 
 | ||||
| @ -15,6 +16,15 @@ app.get("/", (_, res) => { | ||||
| 
 | ||||
| const start = async () => { | ||||
|   // Initialize Payload
 | ||||
| 
 | ||||
|   if (isUndefined(process.env.PAYLOAD_SECRET)) { | ||||
|     throw new Error("Missing required env variable: PAYLOAD_SECRET"); | ||||
|   } | ||||
| 
 | ||||
|   if (isUndefined(process.env.MONGODB_URI)) { | ||||
|     throw new Error("Missing required env variable: MONGODB_URI"); | ||||
|   } | ||||
| 
 | ||||
|   await payload.init({ | ||||
|     secret: process.env.PAYLOAD_SECRET, | ||||
|     mongoURL: process.env.MONGODB_URI, | ||||
| @ -24,19 +34,26 @@ const start = async () => { | ||||
|       const recorders = await payload.find({ collection: Collections.Recorders }); | ||||
| 
 | ||||
|       // If no recorders, we seed some initial data
 | ||||
|       if (recorders.docs.length === 0) { | ||||
|         payload.logger.info("Seeding some initial data"); | ||||
|         const recorder: PayloadCreateData<Recorder> = { | ||||
|           email: process.env.SEEDING_ADMIN_EMAIL, | ||||
|           password: process.env.SEEDING_ADMIN_PASSWORD, | ||||
|           username: process.env.SEEDING_ADMIN_USERNAME, | ||||
|           role: [RecordersRoles.Admin], | ||||
|           anonymize: false, | ||||
|         }; | ||||
|         await payload.create({ | ||||
|           collection: Collections.Recorders, | ||||
|           data: recorder, | ||||
|         }); | ||||
|       if ( | ||||
|         isDefined(process.env.SEEDING_ADMIN_EMAIL) && | ||||
|         isDefined(process.env.SEEDING_ADMIN_PASSWORD) && | ||||
|         isDefined(process.env.SEEDING_ADMIN_USERNAME) | ||||
|       ) { | ||||
|         if (recorders.docs.length === 0) { | ||||
|           payload.logger.info("Seeding some initial data"); | ||||
| 
 | ||||
|           const recorder: PayloadCreateData<Recorder> = { | ||||
|             email: process.env.SEEDING_ADMIN_EMAIL, | ||||
|             password: process.env.SEEDING_ADMIN_PASSWORD, | ||||
|             username: process.env.SEEDING_ADMIN_USERNAME, | ||||
|             role: [RecordersRoles.Admin], | ||||
|             anonymize: false, | ||||
|           }; | ||||
|           await payload.create({ | ||||
|             collection: Collections.Recorders, | ||||
|             data: recorder, | ||||
|           }); | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|   }); | ||||
|  | ||||
| @ -14,7 +14,7 @@ export type CategoryTranslations = { | ||||
| }[]; | ||||
| export type RecorderBiographies = { | ||||
|   language: string | Language; | ||||
|   biography?: string; | ||||
|   biography: string; | ||||
|   id?: string; | ||||
| }[]; | ||||
| export type ContentFoldersTranslation = { | ||||
|  | ||||
							
								
								
									
										8
									
								
								src/types/payload.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/types/payload.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| 
 | ||||
| export type PayloadCreateData<T> = Omit< | ||||
|   T, | ||||
|   "id" | "updatedAt" | "createdAt" | "sizes" | "updatedBy" | ||||
| >; | ||||
| 
 | ||||
| export type CollectionEndpoint = NonNullable<CollectionConfig["endpoints"]>[number]; | ||||
							
								
								
									
										14
									
								
								src/types/strapi.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/types/strapi.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| export type StrapiLanguage = { | ||||
|   data?: { attributes: { code: string } }; | ||||
| }; | ||||
| 
 | ||||
| export type StrapiImage = { | ||||
|   data?: { | ||||
|     attributes: { | ||||
|       url: string; | ||||
|       mime: string; | ||||
|       name: string; | ||||
|       size: number; | ||||
|     }; | ||||
|   }; | ||||
| }; | ||||
| @ -1,5 +1,6 @@ | ||||
| import payload from "payload"; | ||||
| import { Collections, KeysTypes } from "../constants"; | ||||
| import { StrapiImage } from "../types/strapi"; | ||||
| import { isDefined } from "./asserts"; | ||||
| 
 | ||||
| export const findWeaponType = async (name: string): Promise<string> => { | ||||
| @ -23,20 +24,10 @@ type UploadStrapiImage = { | ||||
|   collection: Collections; | ||||
| }; | ||||
| 
 | ||||
| type StrapiImage = { | ||||
|   data?: { | ||||
|     attributes: { | ||||
|       url: string; | ||||
|       mime: string; | ||||
|       name: string; | ||||
|       size: number; | ||||
|     }; | ||||
|   }; | ||||
| }; | ||||
| export const uploadStrapiImage = async ({ | ||||
|   collection, | ||||
|   image, | ||||
| }: UploadStrapiImage): Promise<string> => { | ||||
| }: UploadStrapiImage): Promise<string | undefined> => { | ||||
|   if (isDefined(image.data)) { | ||||
|     const url = `${process.env.STRAPI_URI}${image.data.attributes.url}`; | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { Block, BlockField } from "payload/types"; | ||||
| import { capitalize } from "./string"; | ||||
| 
 | ||||
| const isDefined = <T>(value: T | null | undefined): value is T => | ||||
|   value !== null && value !== undefined; | ||||
| @ -26,11 +27,6 @@ export const generateBlocks = <T extends string>(blocksConfig: BlocksConfig<T>): | ||||
|     recursionFieldName in block; | ||||
| 
 | ||||
|   const getInterfaceName = (parents: T[], currentBlockName: T): string => { | ||||
|     const capitalize = (text: string): string => { | ||||
|       if (text.length === 0) return text; | ||||
|       const [firstLetter, ...rest] = text; | ||||
|       return [firstLetter.toUpperCase(), ...rest].join(""); | ||||
|     }; | ||||
|     return [...parents, currentBlockName] | ||||
|       .map((blockName) => blocksConfig[blockName].block.slug) | ||||
|       .map(capitalize) | ||||
|  | ||||
| @ -1,13 +1,15 @@ | ||||
| import tags from "language-tags"; | ||||
| import { isUndefined } from "./asserts"; | ||||
| 
 | ||||
| export const shortenEllipsis = (text: string, length: number): string => | ||||
|   text.length - 3 > length ? `${text.substring(0, length)}...` : text; | ||||
| 
 | ||||
| export const formatLanguageCode = (code: string): string => | ||||
|   tags(code).valid() ? tags(code).language().descriptions()[0] : code; | ||||
|   tags(code).valid() ? tags(code).language()?.descriptions()[0] ?? code : code; | ||||
| 
 | ||||
| export const capitalize = (string: string): string => { | ||||
|   const [firstLetter, ...otherLetters] = string; | ||||
|   if (isUndefined(firstLetter)) return ""; | ||||
|   return [firstLetter.toUpperCase(), ...otherLetters].join(""); | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +0,0 @@ | ||||
| export type PayloadCreateData<T> = Omit< | ||||
|   T, | ||||
|   "id" | "updatedAt" | "createdAt" | "sizes" | "updatedBy" | ||||
| >; | ||||
							
								
								
									
										120
									
								
								tsconfig.json
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								tsconfig.json
									
									
									
									
									
								
							| @ -1,18 +1,116 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "target": "ES2022", | ||||
|     "moduleResolution": "NodeNext", | ||||
|     "lib": ["dom", "dom.iterable", "esnext"], | ||||
|     "allowJs": true, | ||||
|     "strict": false, | ||||
|     "esModuleInterop": true, | ||||
|     "skipLibCheck": true, | ||||
|     "outDir": "./dist", | ||||
|     "rootDir": "./src", | ||||
|     "jsx": "react", | ||||
|     /* Visit https://aka.ms/tsconfig to read more about this file */ | ||||
| 
 | ||||
|     /* Projects */ | ||||
|     // "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ | ||||
|     // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */ | ||||
|     // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */ | ||||
|     // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */ | ||||
|     // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */ | ||||
|     // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */ | ||||
| 
 | ||||
|     /* Language and Environment */ | ||||
|     "target": "ES2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, | ||||
|     "lib": [ | ||||
|       "dom", | ||||
|       "dom.iterable", | ||||
|       "esnext" | ||||
|     ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, | ||||
|     "jsx": "react" /* Specify what JSX code is generated. */, | ||||
|     // "experimentalDecorators": true,                   /* Enable experimental support for legacy experimental decorators. */ | ||||
|     // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */ | ||||
|     // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ | ||||
|     // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ | ||||
|     // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ | ||||
|     // "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ | ||||
|     // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */ | ||||
|     // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */ | ||||
|     // "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */ | ||||
| 
 | ||||
|     /* Modules */ | ||||
|     "module": "commonjs" /* Specify what module code is generated. */, | ||||
|     "rootDir": "./src" /* Specify the root folder within your source files. */, | ||||
|     // "moduleResolution": "node10",                     /* Specify how TypeScript looks up a file from a given module specifier. */ | ||||
|     // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */ | ||||
|     "paths": { | ||||
|       "payload/generated-types": ["./src/payload-types.ts"] | ||||
|     } | ||||
|     } /* Specify a set of entries that re-map imports to additional lookup locations. */, | ||||
|     // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */ | ||||
|     // "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */ | ||||
|     // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */ | ||||
|     // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */ | ||||
|     // "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */ | ||||
|     // "allowImportingTsExtensions": true,               /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ | ||||
|     // "resolvePackageJsonExports": true,                /* Use the package.json 'exports' field when resolving package imports. */ | ||||
|     // "resolvePackageJsonImports": true,                /* Use the package.json 'imports' field when resolving imports. */ | ||||
|     // "customConditions": [],                           /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ | ||||
|     // "resolveJsonModule": true,                        /* Enable importing .json files. */ | ||||
|     // "allowArbitraryExtensions": true,                 /* Enable importing files with any extension, provided a declaration file is present. */ | ||||
|     // "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */ | ||||
| 
 | ||||
|     /* JavaScript Support */ | ||||
|     // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ | ||||
|     // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */ | ||||
|     // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ | ||||
| 
 | ||||
|     /* Emit */ | ||||
|     // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ | ||||
|     // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */ | ||||
|     // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */ | ||||
|     // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */ | ||||
|     // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */ | ||||
|     // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ | ||||
|     "outDir": "./dist" /* Specify an output folder for all emitted files. */, | ||||
|     // "removeComments": true,                           /* Disable emitting comments. */ | ||||
|     // "noEmit": true,                                   /* Disable emitting files from a compilation. */ | ||||
|     // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ | ||||
|     // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types. */ | ||||
|     // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ | ||||
|     // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */ | ||||
|     // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */ | ||||
|     // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */ | ||||
|     // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ | ||||
|     // "newLine": "crlf",                                /* Set the newline character for emitting files. */ | ||||
|     // "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ | ||||
|     // "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */ | ||||
|     // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */ | ||||
|     // "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */ | ||||
|     // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */ | ||||
|     // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ | ||||
| 
 | ||||
|     /* Interop Constraints */ | ||||
|     // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */ | ||||
|     // "verbatimModuleSyntax": true,                     /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ | ||||
|     // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */ | ||||
|     "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, | ||||
|     // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ | ||||
|     "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, | ||||
| 
 | ||||
|     /* Type Checking */ | ||||
|     "strict": true /* Enable all strict type-checking options. */, | ||||
|     // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */ | ||||
|     // "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */ | ||||
|     // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ | ||||
|     // "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ | ||||
|     // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */ | ||||
|     // "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */ | ||||
|     // "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */ | ||||
|     "alwaysStrict": true /* Ensure 'use strict' is always emitted. */, | ||||
|     // "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */ | ||||
|     // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */ | ||||
|     // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */ | ||||
|     // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */ | ||||
|     "noFallthroughCasesInSwitch": true /* Enable error reporting for fallthrough cases in switch statements. */, | ||||
|     "noUncheckedIndexedAccess": true /* Add 'undefined' to a type when accessed using an index. */, | ||||
|     // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */ | ||||
|     // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */ | ||||
|     // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */ | ||||
|     // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */ | ||||
| 
 | ||||
|     /* Completeness */ | ||||
|     // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */ | ||||
|     "skipLibCheck": true /* Skip type checking all .d.ts files. */ | ||||
|   }, | ||||
|   "include": ["src"], | ||||
|   "exclude": ["node_modules", "dist", "build"], | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint