mirror of
https://github.com/xtr-dev/payload-feature-flags.git
synced 2025-12-10 19:03:25 +00:00
Replace redundant components with updated feature flag hooks and views. Add comprehensive documentation and ESLint config for improved development workflow.
This commit is contained in:
@@ -3,7 +3,7 @@ import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
import { MongoMemoryReplSet } from 'mongodb-memory-server'
|
||||
import path from 'path'
|
||||
import { buildConfig } from 'payload'
|
||||
import { payloadFeatureFlags } from 'payload-feature-flags'
|
||||
import { payloadFeatureFlags } from '../src/index.js'
|
||||
import sharp from 'sharp'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
@@ -18,15 +18,19 @@ if (!process.env.ROOT_DIR) {
|
||||
}
|
||||
|
||||
const buildConfigWithMemoryDB = async () => {
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
// Use in-memory MongoDB for both test and development
|
||||
if (process.env.NODE_ENV === 'test' || process.env.NODE_ENV !== 'production') {
|
||||
console.log('🗃️ Starting MongoDB Memory Server...')
|
||||
const memoryDB = await MongoMemoryReplSet.create({
|
||||
replSet: {
|
||||
count: 3,
|
||||
dbName: 'payloadmemory',
|
||||
count: 1,
|
||||
dbName: 'payload-feature-flags-dev',
|
||||
},
|
||||
})
|
||||
|
||||
process.env.DATABASE_URI = `${memoryDB.getUri()}&retryWrites=true`
|
||||
const uri = memoryDB.getUri()
|
||||
process.env.DATABASE_URI = `${uri}&retryWrites=true`
|
||||
console.log('✅ MongoDB Memory Server started successfully')
|
||||
}
|
||||
|
||||
return buildConfig({
|
||||
@@ -38,11 +42,87 @@ const buildConfigWithMemoryDB = async () => {
|
||||
collections: [
|
||||
{
|
||||
slug: 'posts',
|
||||
fields: [],
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
type: 'select',
|
||||
options: ['draft', 'published'],
|
||||
defaultValue: 'draft',
|
||||
},
|
||||
{
|
||||
name: 'publishedAt',
|
||||
type: 'date',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'pages',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'text',
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
},
|
||||
{
|
||||
name: 'layout',
|
||||
type: 'select',
|
||||
options: ['default', 'landing', 'sidebar'],
|
||||
defaultValue: 'default',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'users',
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
auth: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'role',
|
||||
type: 'select',
|
||||
options: ['admin', 'editor', 'user'],
|
||||
defaultValue: 'user',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'media',
|
||||
fields: [],
|
||||
fields: [
|
||||
{
|
||||
name: 'alt',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
upload: {
|
||||
staticDir: path.resolve(dirname, 'media'),
|
||||
},
|
||||
@@ -50,7 +130,7 @@ const buildConfigWithMemoryDB = async () => {
|
||||
],
|
||||
db: mongooseAdapter({
|
||||
ensureIndexes: true,
|
||||
url: process.env.DATABASE_URI || '',
|
||||
url: process.env.DATABASE_URI || 'mongodb://localhost/payload-feature-flags-dev',
|
||||
}),
|
||||
editor: lexicalEditor(),
|
||||
email: testEmailAdapter,
|
||||
@@ -59,12 +139,94 @@ const buildConfigWithMemoryDB = async () => {
|
||||
},
|
||||
plugins: [
|
||||
payloadFeatureFlags({
|
||||
collections: {
|
||||
posts: true,
|
||||
// Enable all features
|
||||
enableRollouts: true,
|
||||
enableVariants: true,
|
||||
enableApi: true,
|
||||
defaultValue: false,
|
||||
|
||||
// Custom collection configuration
|
||||
collectionOverrides: {
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
group: 'Configuration',
|
||||
description: 'Manage feature flags for the development environment',
|
||||
},
|
||||
access: {
|
||||
// Only authenticated users can read/manage feature flags
|
||||
read: ({ req: { user } }) => !!user,
|
||||
create: ({ req: { user } }) => !!user,
|
||||
update: ({ req: { user } }) => user?.role === 'admin',
|
||||
delete: ({ req: { user } }) => user?.role === 'admin',
|
||||
},
|
||||
fields: ({ defaultFields }) => [
|
||||
...defaultFields,
|
||||
{
|
||||
name: 'environment',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: 'Development', value: 'development' },
|
||||
{ label: 'Staging', value: 'staging' },
|
||||
{ label: 'Production', value: 'production' },
|
||||
],
|
||||
required: true,
|
||||
defaultValue: 'development',
|
||||
admin: {
|
||||
description: 'Which environment this flag applies to',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'owner',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
admin: {
|
||||
description: 'Team member responsible for this feature flag',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'expiresAt',
|
||||
type: 'date',
|
||||
admin: {
|
||||
description: 'Optional expiration date for temporary flags',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'jiraTicket',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Related JIRA ticket or issue number',
|
||||
},
|
||||
},
|
||||
],
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
async ({ data, req, operation }) => {
|
||||
// Auto-assign current user as owner for new flags
|
||||
if (operation === 'create' && !data.owner && req.user) {
|
||||
data.owner = req.user.id
|
||||
}
|
||||
|
||||
// Log flag changes for audit trail
|
||||
if (req.user) {
|
||||
console.log(`Feature flag "${data.name}" ${operation} by ${req.user.email}`)
|
||||
}
|
||||
|
||||
return data
|
||||
},
|
||||
],
|
||||
afterChange: [
|
||||
async ({ doc, req, operation }) => {
|
||||
// Send notification for critical flag changes
|
||||
if (doc.environment === 'production' && req.user) {
|
||||
console.log(`🚨 Production feature flag "${doc.name}" was ${operation === 'create' ? 'created' : 'modified'} by ${req.user.email}`)
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
secret: process.env.PAYLOAD_SECRET || 'test-secret_key',
|
||||
secret: process.env.PAYLOAD_SECRET || 'dev-secret-key-change-in-production',
|
||||
sharp,
|
||||
typescript: {
|
||||
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
||||
|
||||
Reference in New Issue
Block a user