Files
net/scripts/create_page_blocks_schema.js
cawcenter 549250e9c8 feat: Updated task list, added Phase 8 (Block Editor foundation)
Progress Update:
-  Phase 1-3: Complete (Foundation, Navigation, Factory Floor)
-  Collection Pages: All 10 pages built and deployed
-  API Token: Fixed and configured
-  Directus: Configured with Visual Editor
- 🆕 Phase 8: Block Editor foundation (Craft.js + schema)

New Files:
- BLOCK_EDITOR_IMPLEMENTATION_PLAN.md - Full implementation guide
- DIRECTUS_CONFIGURATION.md - Complete Directus setup docs
- scripts/create_page_blocks_schema.js - Schema creation script
- page_blocks collection created in Directus

Progress: 61% complete (100/165 tasks)
Next: Phase 4 - Intelligence Station
2025-12-13 13:56:01 -05:00

251 lines
8.4 KiB
JavaScript

#!/usr/bin/env node
/**
* Create page_blocks collection schema in Directus
* Stores Craft.js block configurations for visual page builder
*/
const DIRECTUS_URL = 'https://spark.jumpstartscaling.com';
const TOKEN = 'Jlh3Ljpa3lp73W6Z3cbG_LZ3vjLYlN-H';
async function createSchema() {
console.log('🔧 Creating page_blocks collection schema...\n');
try {
// 1. Create the collection
console.log('📦 Creating page_blocks collection...');
const collectionResponse = await fetch(`${DIRECTUS_URL}/collections`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
collection: 'page_blocks',
meta: {
collection: 'page_blocks',
icon: 'view_agenda',
note: 'Visual page builder block configurations',
display_template: '{{block_type}} - {{page_id}}',
hidden: false,
singleton: false,
translations: null,
archive_field: null,
archive_app_filter: true,
archive_value: null,
unarchive_value: null,
sort_field: 'order',
accountability: 'all',
color: '#6644FF',
item_duplication_fields: null,
sort: 1,
group: null,
collapse: 'open'
},
schema: {
name: 'page_blocks'
}
})
});
if (!collectionResponse.ok) {
const error = await collectionResponse.text();
console.log('⚠️ Collection may already exist:', error.substring(0, 100));
} else {
console.log('✅ Collection created!');
}
// 2. Create fields
const fields = [
{
field: 'id',
type: 'uuid',
meta: {
hidden: true,
readonly: true,
interface: 'input',
special: ['uuid'],
note: 'Primary key'
},
schema: {
is_primary_key: true,
has_auto_increment: false,
is_nullable: false
}
},
{
field: 'page_id',
type: 'uuid',
meta: {
interface: 'select-dropdown-m2o',
special: ['m2o'],
required: true,
options: {
template: '{{title}}'
},
display: 'related-values',
display_options: {
template: '{{title}}'
},
width: 'half',
note: 'Page this block belongs to'
},
schema: {
is_nullable: false,
foreign_key_table: 'pages',
foreign_key_column: 'id'
}
},
{
field: 'order',
type: 'integer',
meta: {
interface: 'input',
required: true,
width: 'half',
note: 'Display order (0-based)',
options: {
min: 0
}
},
schema: {
is_nullable: false,
default_value: 0
}
},
{
field: 'block_type',
type: 'string',
meta: {
interface: 'select-dropdown',
required: true,
width: 'half',
note: 'Type of content block',
options: {
choices: [
{ text: 'Hero', value: 'hero' },
{ text: 'Features', value: 'features' },
{ text: 'FAQ', value: 'faq' },
{ text: 'Rich Text', value: 'richtext' },
{ text: 'Image', value: 'image' },
{ text: 'CTA', value: 'cta' },
{ text: 'Testimonial', value: 'testimonial' },
{ text: 'Pricing', value: 'pricing' },
{ text: 'Stats', value: 'stats' },
{ text: 'Offer Block', value: 'offer' }
]
}
},
schema: {
is_nullable: false,
max_length: 50
}
},
{
field: 'block_config',
type: 'json',
meta: {
interface: 'input-code',
required: true,
options: {
language: 'json',
template: '{}'
},
note: 'Block configuration and props (JSON)',
width: 'full'
},
schema: {
is_nullable: false
}
},
{
field: 'created_at',
type: 'timestamp',
meta: {
interface: 'datetime',
readonly: true,
hidden: true,
special: ['date-created'],
width: 'half'
},
schema: {
is_nullable: false
}
},
{
field: 'updated_at',
type: 'timestamp',
meta: {
interface: 'datetime',
readonly: true,
hidden: true,
special: ['date-updated'],
width: 'half'
},
schema: {
is_nullable: true
}
}
];
for (const field of fields) {
console.log(`📝 Creating field: ${field.field}...`);
const fieldResponse = await fetch(`${DIRECTUS_URL}/fields/page_blocks`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(field)
});
if (!fieldResponse.ok) {
const error = await fieldResponse.text();
console.log(` ⚠️ May already exist: ${error.substring(0, 80)}`);
} else {
console.log(` ✅ Created ${field.field}`);
}
}
// 3. Create the relation
console.log('\n🔗 Creating page_blocks → pages relation...');
const relationResponse = await fetch(`${DIRECTUS_URL}/relations`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
collection: 'page_blocks',
field: 'page_id',
related_collection: 'pages',
meta: {
one_field: 'blocks',
sort_field: 'order',
one_deselect_action: 'nullify'
},
schema: {
on_delete: 'CASCADE'
}
})
});
if (!relationResponse.ok) {
const error = await relationResponse.text();
console.log('⚠️ Relation may exist:', error.substring(0, 100));
} else {
console.log('✅ Relation created!');
}
console.log('\n🎉 Schema creation complete!\n');
console.log('📊 Collection: page_blocks');
console.log('🔗 Relation: page_blocks.page_id → pages.id (M2O)');
console.log('\n✅ You can now use the visual block editor!');
} catch (error) {
console.error('❌ Error:', error.message);
process.exit(1);
}
}
createSchema();