feat: initial commit

This commit is contained in:
2026-07-08 00:54:30 +02:00
commit 10638127a9
52 changed files with 20041 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
'use client'
import { useConfig } from '@payloadcms/ui'
import { formatAdminURL } from 'payload/shared'
import { useEffect, useState } from 'react'
export const BeforeDashboardClient = () => {
const { config } = useConfig()
const [message, setMessage] = useState('')
useEffect(() => {
const fetchMessage = async () => {
const response = await fetch(
formatAdminURL({
apiRoute: config.routes.api,
path: '/my-plugin-endpoint',
}),
)
const result = await response.json()
setMessage(result.message)
}
void fetchMessage()
}, [config.serverURL, config.routes.api])
return (
<div>
<h1>Added by the plugin: Before Dashboard Client</h1>
<div>
Message from the endpoint:
<div>{message || 'Loading...'}</div>
</div>
</div>
)
}
@@ -0,0 +1,5 @@
.wrapper {
display: flex;
gap: 5px;
flex-direction: column;
}
+19
View File
@@ -0,0 +1,19 @@
import type { ServerComponentProps } from 'payload'
import styles from './BeforeDashboardServer.module.css'
export const BeforeDashboardServer = async (props: ServerComponentProps) => {
const { payload } = props
const { docs } = await payload.find({ collection: 'plugin-collection' })
return (
<div className={styles.wrapper}>
<h1>Added by the plugin: Before Dashboard Server</h1>
Docs from Local API:
{docs.map((doc) => (
<div key={doc.id}>{doc.id}</div>
))}
</div>
)
}
+5
View File
@@ -0,0 +1,5 @@
import type { PayloadHandler } from 'payload'
export const customEndpointHandler: PayloadHandler = () => {
return Response.json({ message: 'Hello from custom endpoint' })
}
+1
View File
@@ -0,0 +1 @@
export { BeforeDashboardClient } from '../components/BeforeDashboardClient.js'
+1
View File
@@ -0,0 +1 @@
export { BeforeDashboardServer } from '../components/BeforeDashboardServer.js'
+113
View File
@@ -0,0 +1,113 @@
import type { CollectionSlug, Config } from 'payload'
import { customEndpointHandler } from './endpoints/customEndpointHandler.js'
export type IpalKitConfig = {
/**
* List of collections to add a custom field
*/
collections?: Partial<Record<CollectionSlug, true>>
disabled?: boolean
}
export const ipalKit =
(pluginOptions: IpalKitConfig) =>
(config: Config): Config => {
if (!config.collections) {
config.collections = []
}
config.collections.push({
slug: 'plugin-collection',
fields: [
{
name: 'id',
type: 'text',
},
],
})
if (pluginOptions.collections) {
for (const collectionSlug in pluginOptions.collections) {
const collection = config.collections.find(
(collection) => collection.slug === collectionSlug,
)
if (collection) {
collection.fields.push({
name: 'addedByPlugin',
type: 'text',
admin: {
position: 'sidebar',
},
})
}
}
}
/**
* If the plugin is disabled, we still want to keep added collections/fields so the database schema is consistent which is important for migrations.
* If your plugin heavily modifies the database schema, you may want to remove this property.
*/
if (pluginOptions.disabled) {
return config
}
if (!config.endpoints) {
config.endpoints = []
}
if (!config.admin) {
config.admin = {}
}
if (!config.admin.components) {
config.admin.components = {}
}
if (!config.admin.components.beforeDashboard) {
config.admin.components.beforeDashboard = []
}
config.admin.components.beforeDashboard.push(
`ipal-kit/client#BeforeDashboardClient`,
)
config.admin.components.beforeDashboard.push(
`ipal-kit/rsc#BeforeDashboardServer`,
)
config.endpoints.push({
handler: customEndpointHandler,
method: 'get',
path: '/my-plugin-endpoint',
})
const incomingOnInit = config.onInit
config.onInit = async (payload) => {
// Ensure we are executing any existing onInit functions before running our own.
if (incomingOnInit) {
await incomingOnInit(payload)
}
const { totalDocs } = await payload.count({
collection: 'plugin-collection',
where: {
id: {
equals: 'seeded-by-plugin',
},
},
})
if (totalDocs === 0) {
await payload.create({
collection: 'plugin-collection',
data: {
id: 'seeded-by-plugin',
},
})
}
}
return config
}