UNPKG

strapi-plugin-generic-custom-fields

Version:
357 lines (356 loc) 9.76 kB
import slugify from "slugify"; import { z } from "zod"; const bootstrap = ({ strapi: _strapi }) => { }; const destroy = ({ strapi: _strapi }) => { }; const strapi = { name: "generic-custom-fields" }; const packageJson = { strapi }; const PLUGIN_ID = packageJson.strapi.name; const register = ({ strapi: strapi2 }) => { const configCustomFields = strapi2.plugin(PLUGIN_ID).config("customFields"); for (const customField of configCustomFields) { strapi2.customFields.register({ name: slugify(customField.name, { lower: true }), plugin: PLUGIN_ID, type: "string", inputSize: customField.inputSize }); } }; const itemResponseSchema = z.object({ value: z.string().min(1), label: z.string().min(1), icon: z.object({ src: z.string(), colorMask: z.boolean().optional() }).optional() }); const itemsResponseSchema = z.object({ items: z.array(itemResponseSchema) // total: z.number().int().min(0).optional(), }); const customFieldSchema = z.object({ name: z.string().min(1), description: z.string().min(1).optional(), icon: z.union([ z.literal("Alien"), z.literal("Archive"), z.literal("ArrowClockwise"), z.literal("ArrowDown"), z.literal("ArrowLeft"), z.literal("ArrowLineLeft"), z.literal("ArrowLineRight"), z.literal("ArrowRight"), z.literal("ArrowUp"), z.literal("ArrowsCounterClockwise"), z.literal("ArrowsOut"), z.literal("Bell"), z.literal("Bold"), z.literal("Book"), z.literal("Briefcase"), z.literal("BulletList"), z.literal("Calendar"), z.literal("Car"), z.literal("CaretDown"), z.literal("CaretUp"), z.literal("Cast"), z.literal("CastleTurret"), z.literal("ChartBubble"), z.literal("ChartCircle"), z.literal("ChartPie"), z.literal("Check"), z.literal("CheckCircle"), z.literal("CheckCircleEmpty"), z.literal("ChevronDown"), z.literal("ChevronLeft"), z.literal("ChevronRight"), z.literal("ChevronUp"), z.literal("Clock"), z.literal("ClockCounterClockwise"), z.literal("Cloud"), z.literal("CloudUpload"), z.literal("Code"), z.literal("CodeBlock"), z.literal("Coffee"), z.literal("Cog"), z.literal("Collapse"), z.literal("Command"), z.literal("Crop"), z.literal("Cross"), z.literal("CrossCircle"), z.literal("Crown"), z.literal("Cursor"), z.literal("Database"), z.literal("Discuss"), z.literal("Download"), z.literal("Drag"), z.literal("Duplicate"), z.literal("Earth"), z.literal("EarthStriked"), z.literal("EmotionHappy"), z.literal("EmotionUnhappy"), z.literal("Expand"), z.literal("ExternalLink"), z.literal("Eye"), z.literal("EyeStriked"), z.literal("Faders"), z.literal("Feather"), z.literal("File"), z.literal("FileCsv"), z.literal("FileError"), z.literal("FilePdf"), z.literal("FileXls"), z.literal("FileZip"), z.literal("Filter"), z.literal("Folder"), z.literal("Gift"), z.literal("Globe"), z.literal("GraphQl"), z.literal("GridFour"), z.literal("GridNine"), z.literal("HandHeart"), z.literal("Hashtag"), z.literal("HeadingFive"), z.literal("HeadingFour"), z.literal("HeadingOne"), z.literal("HeadingSix"), z.literal("HeadingThree"), z.literal("HeadingTwo"), z.literal("Headphones"), z.literal("Heart"), z.literal("House"), z.literal("Image"), z.literal("Images"), z.literal("IndentDecrease"), z.literal("IndentIncrease"), z.literal("Information"), z.literal("Italic"), z.literal("Key"), z.literal("Layout"), z.literal("Lightbulb"), z.literal("Lightning"), z.literal("Link"), z.literal("List"), z.literal("ListPlus"), z.literal("ListSearch"), z.literal("Loader"), z.literal("Lock"), z.literal("Magic"), z.literal("Mail"), z.literal("ManyToMany"), z.literal("ManyToOne"), z.literal("ManyWays"), z.literal("Message"), z.literal("Microphone"), z.literal("Minus"), z.literal("MinusCircle"), z.literal("Monitor"), z.literal("Moon"), z.literal("More"), z.literal("Move"), z.literal("MusicNotes"), z.literal("NumberList"), z.literal("OneToMany"), z.literal("OneToOne"), z.literal("OneWay"), z.literal("PaintBrush"), z.literal("PaintRoller"), z.literal("Palette"), z.literal("PaperPlane"), z.literal("Paperclip"), z.literal("Paragraph"), z.literal("Pencil"), z.literal("Phone"), z.literal("Pin"), z.literal("PinMap"), z.literal("Plane"), z.literal("Plant"), z.literal("Play"), z.literal("Plus"), z.literal("PlusCircle"), z.literal("PresentationChart"), z.literal("PriceTag"), z.literal("PuzzlePiece"), z.literal("Question"), z.literal("Quotes"), z.literal("Restaurant"), z.literal("Rocket"), z.literal("Scissors"), z.literal("SealCheck"), z.literal("Search"), z.literal("Server"), z.literal("Shield"), z.literal("Shirt"), z.literal("ShoppingCart"), z.literal("SignOut"), z.literal("SlidersHorizontal"), z.literal("Sparkle"), z.literal("SquaresFour"), z.literal("Stack"), z.literal("Star"), z.literal("Stethoscope"), z.literal("Stop"), z.literal("Store"), z.literal("StrikeThrough"), z.literal("Sun"), z.literal("Television"), z.literal("ThumbDown"), z.literal("ThumbUp"), z.literal("Train"), z.literal("Trash"), z.literal("Typhoon"), z.literal("Underline"), z.literal("Upload"), z.literal("User"), z.literal("VolumeMute"), z.literal("VolumeUp"), z.literal("Walk"), z.literal("WarningCircle"), z.literal("Wheelchair") ]).optional(), inputSize: z.object({ default: z.union([z.literal(4), z.literal(6), z.literal(8), z.literal(12)]), isResizable: z.boolean() }).optional(), searchable: z.boolean().optional(), fetchItems: z.function().args(z.object({ query: z.string().optional() })).returns(z.union([itemsResponseSchema, z.promise(itemsResponseSchema)])), fetchItem: z.function().args(z.object({ value: z.string() })).returns(z.union([itemResponseSchema, z.promise(itemResponseSchema)])) }); const configSchema = z.object({ customFields: z.array(customFieldSchema).refine( (fields) => { const slugifiedNames = fields.map((field) => slugify(field.name, { lower: true })); return new Set(slugifiedNames).size === slugifiedNames.length; }, { message: "Each custom field name must be unique after slugification" } ) }); const config = { default: { customFields: [] }, validator(config2) { configSchema.parse(config2); } }; const contentTypes = {}; const controller = ({ strapi: strapi2 }) => ({ getConfigCustomFields() { return strapi2.plugin(PLUGIN_ID).config("customFields"); }, getCustomFieldUID(name) { return `plugin::${PLUGIN_ID}.${slugify(name, { lower: true })}`; }, configCustomFields() { return this.getConfigCustomFields(); }, configCustomField(ctx) { const customFields = this.getConfigCustomFields(); const customField = customFields.find((field) => ctx.params.uid === this.getCustomFieldUID(field.name)); if (!customField) { ctx.throw(404, `Custom field ${ctx.params.uid} not found`); } return customField; }, async customFieldItems(ctx) { try { const customFields = this.getConfigCustomFields(); const customField = customFields.find((field) => ctx.params.uid === this.getCustomFieldUID(field.name)); if (!customField) { ctx.throw(404, `Custom field ${ctx.params.uid} not found`); } const query = ctx.request.query.query; return itemsResponseSchema.parse(await customField.fetchItems({ query // page: page ? parseInt(page, 10) : undefined, })); } catch (error) { throw error instanceof Error ? error : new Error(`Error fetching CustomField[${ctx.params.uid}] items: ${error}`); } }, async customFieldItem(ctx) { try { const customFields = this.getConfigCustomFields(); const customField = customFields.find((field) => ctx.params.uid === this.getCustomFieldUID(field.name)); if (!customField) { ctx.throw(404, `Custom field ${ctx.params.uid} not found`); } const value = ctx.request.query.value; return itemResponseSchema.parse(await customField.fetchItem({ value })); } catch (error) { throw error instanceof Error ? error : new Error(`Error fetching CustomField[${ctx.params.uid}] item: ${error}`); } } }); const controllers = { admin: controller }; const middlewares = {}; const policies = {}; const adminRoutes = [ { method: "GET", path: "/config/custom-fields", handler: "admin.configCustomFields", config: { policies: ["admin::isAuthenticatedAdmin"] } }, { method: "GET", path: "/config/custom-fields/:uid", handler: "admin.configCustomField", config: { policies: ["admin::isAuthenticatedAdmin"] } }, { method: "GET", path: "/custom-fields/:uid/items", handler: "admin.customFieldItems", config: { policies: ["admin::isAuthenticatedAdmin"] } }, { method: "GET", path: "/custom-fields/:uid/item", handler: "admin.customFieldItem", config: { policies: ["admin::isAuthenticatedAdmin"] } } ]; const routes = { admin: { type: "admin", routes: adminRoutes } }; const services = {}; const index = { register, bootstrap, destroy, config, controllers, routes, services, contentTypes, policies, middlewares }; export { index as default };