Implement proper Payload CMS DefaultTemplate layout integration

Layout Implementation:
- Fixed import to use DefaultTemplate from '@payloadcms/next/templates'
- Added proper template props interface with i18n, locale, payload, etc.
- Restructured component to use DefaultTemplate wrapper correctly
- Created FeatureFlagsContent as child component for template

Template Structure:
- Component now receives standard Payload admin view props
- DefaultTemplate provides proper admin layout with sidebar navigation
- All template props (i18n, locale, params, payload, permissions, etc.) are passed through
- Maintains theme integration and responsive design within admin layout

The feature flags dashboard now properly integrates with Payload's admin
layout system, including the navigation sidebar and standard admin styling,
while preserving all spreadsheet functionality and inline editing capabilities.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-03 16:16:42 +02:00
parent 4091141722
commit 98cab95411

View File

@@ -4,6 +4,7 @@ import {
useConfig, useConfig,
useTheme useTheme
} from '@payloadcms/ui' } from '@payloadcms/ui'
import { DefaultTemplate } from '@payloadcms/next/templates'
interface FeatureFlag { interface FeatureFlag {
id: string id: string
@@ -24,11 +25,17 @@ interface FeatureFlag {
} }
interface FeatureFlagsViewProps { interface FeatureFlagsViewProps {
// Props that would typically be passed from the parent view i18n?: any
[key: string]: any locale?: any
params?: any
payload?: any
permissions?: any
searchParams?: any
user?: any
visibleEntities?: any
} }
const FeatureFlagsViewComponent = (props: FeatureFlagsViewProps = {}) => { const FeatureFlagsViewComponent = (props: FeatureFlagsViewProps) => {
const { config } = useConfig() const { config } = useConfig()
const { theme } = useTheme() const { theme } = useTheme()
const [flags, setFlags] = useState<FeatureFlag[]>([]) const [flags, setFlags] = useState<FeatureFlag[]>([])
@@ -197,80 +204,72 @@ const FeatureFlagsViewComponent = (props: FeatureFlagsViewProps = {}) => {
const styles = getThemeStyles() const styles = getThemeStyles()
if (loading) { const FeatureFlagsContent = () => (
return (
<div style={{
padding: '2rem',
textAlign: 'center',
minHeight: '400px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<div style={{ fontSize: '1.125rem', color: styles.textMuted }}>Loading feature flags...</div>
</div>
)
}
return (
<div style={{ <div style={{
padding: '0', padding: '2rem',
height: '100%', maxWidth: '100%'
overflow: 'auto'
}}> }}>
{/* Content Container */} {/* Header */}
<div style={{ <div style={{ marginBottom: '2rem' }}>
padding: '2rem', <h1 style={{
maxWidth: '100%' fontSize: '2rem',
}}> fontWeight: '700',
{/* Header */} color: styles.text,
<div style={{ marginBottom: '2rem' }}> margin: '0 0 0.5rem 0'
<h1 style={{
fontSize: '2rem',
fontWeight: '700',
color: styles.text,
margin: '0 0 0.5rem 0'
}}>
Feature Flags Dashboard
</h1>
<p style={{
color: styles.textMuted,
fontSize: '1rem',
margin: '0 0 2rem 0'
}}>
Manage all feature flags in a spreadsheet view with inline editing capabilities
</p>
</div>
{/* Success/Error Messages */}
{successMessage && (
<div style={{
position: 'fixed',
top: '20px',
right: '20px',
backgroundColor: styles.primary,
color: 'white',
padding: '0.75rem 1.5rem',
borderRadius: '0.5rem',
boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
zIndex: 1000,
}}> }}>
{successMessage} Feature Flags Dashboard
</div> </h1>
)} <p style={{
color: styles.textMuted,
{error && ( fontSize: '1rem',
<div style={{ margin: '0 0 2rem 0'
marginBottom: '1rem',
backgroundColor: styles.error + '20',
border: `1px solid ${styles.error}`,
borderRadius: '0.5rem',
padding: '1rem',
color: styles.error
}}> }}>
<strong>Error:</strong> {error} Manage all feature flags in a spreadsheet view with inline editing capabilities
</p>
</div>
{loading ? (
<div style={{
padding: '2rem',
textAlign: 'center',
minHeight: '400px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<div style={{ fontSize: '1.125rem', color: styles.textMuted }}>Loading feature flags...</div>
</div> </div>
)} ) : (
<>
{/* Success/Error Messages */}
{successMessage && (
<div style={{
position: 'fixed',
top: '20px',
right: '20px',
backgroundColor: styles.primary,
color: 'white',
padding: '0.75rem 1.5rem',
borderRadius: '0.5rem',
boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
zIndex: 1000,
}}>
{successMessage}
</div>
)}
{error && (
<div style={{
marginBottom: '1rem',
backgroundColor: styles.error + '20',
border: `1px solid ${styles.error}`,
borderRadius: '0.5rem',
padding: '1rem',
color: styles.error
}}>
<strong>Error:</strong> {error}
</div>
)}
{/* Controls */} {/* Controls */}
<div style={{ <div style={{
@@ -619,9 +618,25 @@ const FeatureFlagsViewComponent = (props: FeatureFlagsViewProps = {}) => {
<span style={{ fontWeight: '600' }}>A/B Tests:</span> {flags.filter(f => f && f.variants && f.variants.length > 0).length} <span style={{ fontWeight: '600' }}>A/B Tests:</span> {flags.filter(f => f && f.variants && f.variants.length > 0).length}
</div> </div>
</div> </div>
</div> </>
)}
</div> </div>
) )
return (
<DefaultTemplate
i18n={props.i18n}
locale={props.locale}
params={props.params}
payload={props.payload}
permissions={props.permissions}
searchParams={props.searchParams}
user={props.user}
visibleEntities={props.visibleEntities}
>
<FeatureFlagsContent />
</DefaultTemplate>
)
} }
export const FeatureFlagsView = memo(FeatureFlagsViewComponent) export const FeatureFlagsView = memo(FeatureFlagsViewComponent)