Skip to content

Commit caf750d

Browse files
AzGasimcursoragent
andauthored
Feature/custom fields (#1001)
* initial commit * Fix styling * validation * Fix styling * new fieldtypes * Fix styling * Purge custom field values when a field group is deleted * new fields * repeater, groups, tabs * validation * Fix styling * Fix styling * flexible layout * Fix styling * Update README * mprove builder MVP: tabs, validation, value migration, and admin UX * fix fields * fix color field * fix date picker * fix date time picker * fix email field * fix flexible content field * fix group field * Fix styling * fix link field * Fix styling * fix message field * fix number field * fix password field * fix radio button field * fix range field * fix repeater field * Fix styling * fix rich text field * fix select field * fix tab field * fix time field * Fix styling * fix toggle field * fix embed field * Fix styling * fix default value * Add InteractsWithCustomFields for native model custom field access and API output * Fix styling * Add image custom field with media picker and usage tracking * Fix styling * Add gallery custom field with scoped media validation and picker isolation * Fix styling * Add file custom field and scope media picker lists by mime type * update README * update readme * Add locale-aware translations for builder field definitions and values. * Wire admin locale automatically for HasCustomFields resources. * Gate custom field value locales by entity translatability * Fix styling * Make moox/builder integration optional via core bridge traits Consumers (item, record, draft) now use Moox\Core\Traits\HasCustomFields and InteractsWithCustomFields instead of depending on moox/builder directly. The core traits alias the real builder traits when the package is installed and fall back to empty stubs otherwise, mirroring the HasRolesTrait pattern. BaseResource provides a no-op customFieldComponents() so resource forms render without a fatal error when builder is absent. * make builder optional * Add configurable custom field table columns * Add per-context visibility for builder fields and groups * Add field group placement, layout widths and section markers * Improve field builder UX in FieldGroupResource * Add per-group column layout for field groups * Add relation field type with entity linking, validation, and table columns * Add conditional logic for builder field visibility * Fix narrow tab rendering in compiled custom field forms * Harden builder custom fields and trim dead code * update readme * Sanitize TipTap JSON rich text on persist via Filament * Add field group definition import/export in admin * Fix styling * Add sortable and searchable relation field table columns * Align field hint icons beside labels in admin forms * Refine builder location conditions * Improve builder field validation * Fix styling * improve color field * Fix styling * Refine builder table columns * Fix stale assignment conditions when target entities change * Harden builder definition imports * Improve builder condition editor feedback * Fix styling * Refine builder conditions and validation workflows * Fix styling * Reduce builder query load for field groups and custom field resources. * Fix location rules when record params are missing * Harden builder validation rules and remove dead field-type APIs * Add Quick Start onboarding section to builder README * Remove deprecated ReflectionProperty::setAccessible call * Skip Swiss German (gsw) variant during static data import * Clean up user-session install defaults * Add comprehensive builder test suite for custom fields runtime * Fix styling * Fix relation picker labels for translation-backed targets * Document relation label resolution in builder README * Fix relation column search for translation-backed targets * Fix styling * fix data import job * Add record_status location rule for custom field groups * Fix styling * Fix empty taxonomy term options in location rule value select * Add opt-in table filters for custom field list views Co-authored-by: Cursor <cursoragent@cursor.com> * Fix styling * update readme and use more name field options * Fix styling --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 2fb48c3 commit caf750d

230 files changed

Lines changed: 34769 additions & 23 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/builder/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/vendor
2+
.phpunit.result.cache
3+
composer.lock

packages/builder/README.md

Lines changed: 1180 additions & 0 deletions
Large diffs are not rendered by default.

packages/builder/composer.json

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
{
2+
"name": "moox/builder",
3+
"description": "Runtime custom field groups for Filament resources with typed value storage.",
4+
"keywords": [
5+
"Moox",
6+
"Laravel",
7+
"Filament",
8+
"Moox package",
9+
"Laravel package",
10+
"Custom fields"
11+
],
12+
"homepage": "https://moox.org/docs/builder",
13+
"license": "MIT",
14+
"authors": [
15+
{
16+
"name": "Moox Developer",
17+
"email": "dev@moox.org",
18+
"role": "Developer"
19+
}
20+
],
21+
"require": {
22+
"moox/core": "dev-main"
23+
},
24+
"autoload": {
25+
"psr-4": {
26+
"Moox\\Builder\\": "src",
27+
"Moox\\Builder\\Database\\Seeders\\": "database/seeders"
28+
}
29+
},
30+
"autoload-dev": {
31+
"psr-4": {
32+
"Moox\\Builder\\Tests\\": "tests/",
33+
"Moox\\Builder\\Tests\\Support\\": "tests/Support/"
34+
}
35+
},
36+
"extra": {
37+
"laravel": {
38+
"providers": [
39+
"Moox\\Builder\\BuilderServiceProvider"
40+
]
41+
},
42+
"moox": {
43+
"name": "Moox Builder",
44+
"stability": "stable",
45+
"type": "moox-plugin",
46+
"install": {
47+
"auto_migrate": "database/migrations",
48+
"seed": "database/seeders/BuilderSeeder.php",
49+
"auto_publish": "builder-config",
50+
"plugins": [
51+
"Moox\\Builder\\Plugins\\BuilderPlugin"
52+
]
53+
},
54+
"update": {
55+
"migrate": "database/migrations",
56+
"merge": "builder-config"
57+
},
58+
"uninstall": {
59+
"migrate": "database/migrations",
60+
"remove": "builder-config"
61+
}
62+
}
63+
},
64+
"minimum-stability": "dev",
65+
"prefer-stable": true,
66+
"require-dev": {
67+
"moox/devtools": "dev-main",
68+
"pestphp/pest": "^4.7",
69+
"pestphp/pest-plugin-livewire": "^4.0"
70+
},
71+
"scripts": {
72+
"test": [
73+
"@php ../../vendor/bin/pest"
74+
],
75+
"format": [
76+
"@php ../../vendor/bin/pint"
77+
]
78+
},
79+
"config": {
80+
"allow-plugins": {
81+
"pestphp/pest-plugin": true
82+
}
83+
}
84+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
return [
6+
'navigation_group' => env('BUILDER_NAVIGATION_GROUP', 'Felder'),
7+
'default_locale' => env('BUILDER_DEFAULT_LOCALE', 'en_US'),
8+
];
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Database\Migrations\Migration;
6+
use Illuminate\Database\Schema\Blueprint;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
return new class extends Migration
10+
{
11+
public function up(): void
12+
{
13+
Schema::create('builder_field_group_translations', function (Blueprint $table): void {
14+
$table->id();
15+
$table->foreignId('field_group_id')->constrained('builder_field_groups')->cascadeOnDelete();
16+
$table->string('locale');
17+
$table->string('name');
18+
$table->timestamps();
19+
20+
$table->unique(['field_group_id', 'locale']);
21+
$table->index('locale');
22+
});
23+
}
24+
25+
public function down(): void
26+
{
27+
Schema::dropIfExists('builder_field_group_translations');
28+
}
29+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
public function up(): void
10+
{
11+
Schema::create('builder_field_groups', function (Blueprint $table): void {
12+
$table->id();
13+
$table->ulid('ulid')->unique();
14+
$table->string('name');
15+
$table->string('slug')->unique();
16+
$table->json('location_rules');
17+
$table->string('placement')->default('default');
18+
$table->json('settings')->nullable();
19+
$table->integer('sort')->default(0);
20+
$table->boolean('active')->default(true);
21+
$table->timestamps();
22+
});
23+
}
24+
25+
public function down(): void
26+
{
27+
Schema::dropIfExists('builder_field_groups');
28+
}
29+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Database\Migrations\Migration;
6+
use Illuminate\Database\Schema\Blueprint;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
return new class extends Migration
10+
{
11+
public function up(): void
12+
{
13+
Schema::create('builder_field_option_translations', function (Blueprint $table): void {
14+
$table->id();
15+
$table->foreignId('field_option_id')->constrained('builder_field_options')->cascadeOnDelete();
16+
$table->string('locale');
17+
$table->string('label');
18+
$table->timestamps();
19+
20+
$table->unique(['field_option_id', 'locale']);
21+
$table->index('locale');
22+
});
23+
}
24+
25+
public function down(): void
26+
{
27+
Schema::dropIfExists('builder_field_option_translations');
28+
}
29+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
public function up(): void
10+
{
11+
Schema::create('builder_field_options', function (Blueprint $table): void {
12+
$table->id();
13+
$table->ulid('ulid')->unique();
14+
$table->foreignId('field_id')->constrained('builder_fields')->cascadeOnDelete();
15+
$table->string('label');
16+
$table->string('value');
17+
$table->integer('sort')->default(0);
18+
$table->timestamps();
19+
});
20+
}
21+
22+
public function down(): void
23+
{
24+
Schema::dropIfExists('builder_field_options');
25+
}
26+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Database\Migrations\Migration;
6+
use Illuminate\Database\Schema\Blueprint;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
return new class extends Migration
10+
{
11+
public function up(): void
12+
{
13+
Schema::create('builder_field_translations', function (Blueprint $table): void {
14+
$table->id();
15+
$table->foreignId('field_id')->constrained('builder_fields')->cascadeOnDelete();
16+
$table->string('locale');
17+
$table->string('label');
18+
$table->json('config')->nullable();
19+
$table->timestamps();
20+
21+
$table->unique(['field_id', 'locale']);
22+
$table->index('locale');
23+
});
24+
}
25+
26+
public function down(): void
27+
{
28+
Schema::dropIfExists('builder_field_translations');
29+
}
30+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Database\Migrations\Migration;
6+
use Illuminate\Database\Schema\Blueprint;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
return new class extends Migration
10+
{
11+
public function up(): void
12+
{
13+
Schema::create('builder_field_values', function (Blueprint $table): void {
14+
$table->id();
15+
$table->string('entity');
16+
$table->unsignedBigInteger('record_id');
17+
$table->string('field_name');
18+
$table->string('locale')->default('en_US');
19+
$table->string('value_string')->nullable();
20+
$table->text('value_text')->nullable();
21+
$table->decimal('value_decimal', 20, 6)->nullable();
22+
$table->date('value_date')->nullable();
23+
$table->dateTime('value_datetime')->nullable();
24+
$table->boolean('value_boolean')->nullable();
25+
$table->json('value_json')->nullable();
26+
$table->timestamps();
27+
28+
$table->unique(['entity', 'record_id', 'field_name', 'locale']);
29+
$table->index(['entity', 'record_id', 'locale']);
30+
$table->index(['entity', 'field_name', 'value_decimal']);
31+
$table->index(['entity', 'field_name', 'value_date']);
32+
$table->index(['entity', 'field_name', 'value_datetime']);
33+
$table->index(['entity', 'record_id']);
34+
});
35+
}
36+
37+
public function down(): void
38+
{
39+
Schema::dropIfExists('builder_field_values');
40+
}
41+
};

0 commit comments

Comments
 (0)