Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e2b7a5e
schemas (wip)
Baspa Sep 10, 2025
94e4faa
add selecttree
Baspa Sep 10, 2025
a65a64f
add grouping
Baspa Sep 10, 2025
e6b7459
Fix styling
Baspa Sep 10, 2025
fb0f224
add fieldset schema
Baspa Sep 10, 2025
51dcc2c
Merge branch 'feat/form-layout-components' of github.com:backstagephp…
Baspa Sep 10, 2025
359e53f
Fix styling
Baspa Sep 10, 2025
2ebe975
use get key name
Baspa Sep 10, 2025
5af1ebf
new trait to render schemas with fields
Baspa Sep 10, 2025
a1041c0
Merge branch 'feat/form-layout-components' of github.com:backstagephp…
Baspa Sep 10, 2025
0b0bc41
Fix styling
Baspa Sep 10, 2025
66257c7
feat: table columns in repeater
Baspa Sep 11, 2025
852de44
wip (needs to be tested thoroughly, also in Backstage)
Baspa Sep 18, 2025
da63411
test
Baspa Sep 18, 2025
bcd799f
Merge branch 'feat/form-layout-components' of github.com:backstagephp…
Baspa Sep 18, 2025
91720fb
Merge branch 'main' of github.com:backstagephp/fields into feat/form-…
Baspa Sep 26, 2025
d130fdb
Fix styling
Baspa Sep 26, 2025
6ee4055
wip?
Baspa Oct 1, 2025
d5f6804
Merge branch 'feat/form-layout-components' of github.com:backstagephp…
Baspa Oct 10, 2025
1365c2c
Merge branch 'main' into feat/form-layout-components
Baspa Oct 10, 2025
ab1030f
Fix styling
Baspa Oct 10, 2025
c61d623
fix: phpstan issue
Baspa Oct 10, 2025
037c057
fix: tests
Baspa Oct 10, 2025
ba61ff4
wip
Baspa Oct 10, 2025
a37e651
Merge branch 'main' into feat/form-layout-components
Baspa Dec 11, 2025
5c3fdae
Update Repeater to exclusively use tableMode
Baspa Dec 11, 2025
8c82d52
repeater improvements
Baspa Dec 11, 2025
b75a1bf
styles: fix styling issues
Baspa Dec 11, 2025
e02ce68
fix phpstan issues
Baspa Dec 11, 2025
ba26403
Merge branch 'feat/form-layout-components' of github.com:backstagephp…
Baspa Dec 11, 2025
ec0cad2
styles: fix styling issues
Baspa Dec 11, 2025
4587a32
remove logs
Baspa Dec 11, 2025
fa7d746
fix: resolve Field enum/model naming conflict in Schema relationships
Baspa Jan 28, 2026
663884e
styles: fix styling issues
Baspa Jan 28, 2026
bc3fecf
test: trigger workflow
Baspa Jan 28, 2026
c6b8dca
Merge branch 'feat/form-layout-components' of github.com:backstagephp…
Baspa Jan 28, 2026
65b2d66
test: trigger workflow
Baspa Jan 28, 2026
52d0d64
Merge branch 'main' into feat/form-layout-components
Baspa Jan 28, 2026
47b498f
fix: downgrade Pest to v3 for PHPUnit compatibility and update tests …
cursoragent Jan 28, 2026
50b8a4a
fix: ensure null values are set in form data for Select fields
cursoragent Jan 28, 2026
3e31356
fix: remove CanMapDynamicFields from Schema model and clean up unreac…
cursoragent Jan 28, 2026
310a807
feat: support both Pest v3 and v4 with flexible version constraints
cursoragent Jan 28, 2026
2906e26
fix: add backward compatibility and data migrations
cursoragent Jan 28, 2026
14536b9
fix: add lazy initialization for fieldInspector to prevent breaking c…
cursoragent Jan 28, 2026
0129914
styles: fix styling issues
cursor[bot] Jan 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest]
php: [8.3]
laravel: [12.*]
laravel: [11.*]
include:
- laravel: 12.*
testbench: 10.*
carbon: 3.*
- laravel: 11.*
testbench: 9.*
carbon: 2.*|3.*

name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.os }}

Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
"laravel/pint": "^1.14",
"nunomaduro/collision": "^8.1.1||^7.10.0",
"nunomaduro/larastan": "^3.0",
"orchestra/testbench": "^9.0.0",
"pestphp/pest": "^4.1",
"pestphp/pest-plugin-arch": "^4.0",
"pestphp/pest-plugin-laravel": "^4.0",
"orchestra/testbench": "^9.0.0|^10.0",
"pestphp/pest": "^3.0|^4.0",
"pestphp/pest-plugin-arch": "^3.0|^4.0",
"pestphp/pest-plugin-laravel": "^3.0|^4.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-phpunit": "^2.0"
Expand Down
24 changes: 24 additions & 0 deletions database/migrations/add_schema_id_to_fields_table.php.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::table('fields', function (Blueprint $table) {
$table->ulid('schema_id')->nullable()->after('group');
$table->foreign('schema_id')->references('ulid')->on('schemas')->onDelete('set null');
});
}

public function down()
{
Schema::table('fields', function (Blueprint $table) {
$table->dropForeign(['schema_id']);
$table->dropColumn('schema_id');
});
}
};
35 changes: 35 additions & 0 deletions database/migrations/create_schemas_table.php.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::create('schemas', function (Blueprint $table) {
$table->ulid('ulid')->primary();
$table->string('name');
$table->string('slug');
$table->string('field_type');
$table->json('config')->nullable();
$table->integer('position')->default(0);
$table->string('model_type');
$table->string('model_key');
$table->ulid('parent_ulid')->nullable();
$table->timestamps();

$table->index(['model_type', 'model_key']);
$table->index(['model_type', 'model_key', 'position']);
$table->index(['parent_ulid']);

$table->unique(['model_type', 'model_key', 'slug']);
});
}

public function down(): void
{
Schema::dropIfExists('schemas');
}
};
90 changes: 90 additions & 0 deletions database/migrations/migrate_model_type_to_class_names.php.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;

return new class extends Migration
{
public function up(): void
{
// Migrate old 'setting' model_type to actual class names
// This ensures backward compatibility for fields created before the PR

$fields = DB::table('fields')
->where('model_type', 'setting')
->get();

foreach ($fields as $field) {
// Try to determine the actual model class
// You may need to customize this logic based on your application
$modelClass = $this->resolveModelClass($field);

if ($modelClass) {
DB::table('fields')
->where('ulid', $field->ulid)
->update(['model_type' => $modelClass]);
}
}

// Do the same for schemas table if it exists
if (DB::getSchemaBuilder()->hasTable('schemas')) {
$schemas = DB::table('schemas')
->where('model_type', 'setting')
->get();

foreach ($schemas as $schema) {
$modelClass = $this->resolveModelClass($schema);

if ($modelClass) {
DB::table('schemas')
->where('ulid', $schema->ulid)
->update(['model_type' => $modelClass]);
}
}
}
}

public function down(): void
{
// Revert to 'setting' for fields that were migrated
// This is a simple revert - you may want to customize based on your needs

DB::table('fields')
->where('model_type', 'like', '%\\\\%') // Contains namespace separator
->update(['model_type' => 'setting']);

if (DB::getSchemaBuilder()->hasTable('schemas')) {
DB::table('schemas')
->where('model_type', 'like', '%\\\\%')
->update(['model_type' => 'setting']);
}
}

/**
* Resolve the actual model class from the field/schema record
*
* Customize this method based on your application's model structure
*/
private function resolveModelClass(object $record): ?string
{
// Check if model_key matches common patterns
// This is a basic example - adjust to your app's structure

// If you have a specific model that fields/schemas attach to, use it
// For example, if all fields belong to forms:
if (class_exists('App\\Models\\Form')) {
return 'App\\Models\\Form';
}

// If you have a settings model:
if (class_exists('App\\Models\\Setting')) {
return 'App\\Models\\Setting';
}

// Try to infer from model_key if it contains model information
// You may need to add custom logic here based on your app

// Return null if we can't determine - will skip this record
return null;
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;

return new class extends Migration
{
public function up(): void
{
// Migrate repeater fields from 'table' config to 'tableMode'
// This ensures backward compatibility

$repeaterFields = DB::table('fields')
->where('field_type', 'repeater')
->whereNotNull('config')
->get();

foreach ($repeaterFields as $field) {
$config = json_decode($field->config, true);

if (! is_array($config)) {
continue;
}

// If 'table' config exists and 'tableMode' doesn't, migrate it
if (isset($config['table']) && ! isset($config['tableMode'])) {
$config['tableMode'] = $config['table'];

// Optionally remove the old 'table' key to clean up
// Uncomment the next line if you want to remove the old key
// unset($config['table']);

DB::table('fields')
->where('ulid', $field->ulid)
->update(['config' => json_encode($config)]);
}
}
}

public function down(): void
{
// Revert 'tableMode' back to 'table' for backward compatibility

$repeaterFields = DB::table('fields')
->where('field_type', 'repeater')
->whereNotNull('config')
->get();

foreach ($repeaterFields as $field) {
$config = json_decode($field->config, true);

if (! is_array($config)) {
continue;
}

// If 'tableMode' exists, migrate it back to 'table'
if (isset($config['tableMode'])) {
$config['table'] = $config['tableMode'];
unset($config['tableMode']);

DB::table('fields')
->where('ulid', $field->ulid)
->update(['config' => json_encode($config)]);
}
}
}
};
Loading