diff --git a/.github/workflows/setup-in-laravel.yml b/.github/workflows/setup-in-laravel.yml index ed52424e..adc09007 100644 --- a/.github/workflows/setup-in-laravel.yml +++ b/.github/workflows/setup-in-laravel.yml @@ -61,6 +61,6 @@ jobs: composer config minimum-stability dev git clone --branch ${{ steps.extract_branch.outputs.branch }} https://github.com/backstagephp/cms.git composer config repositories.backstage-packages path "cms/packages/*" - composer require backstage/cms:dev-${{ steps.extract_branch.outputs.branch }} + composer require backstage/cms:${{ steps.extract_branch.outputs.branch }}-dev composer update --no-interaction php artisan backstage:install diff --git a/composer.json b/composer.json index 4d840df5..65fe0d66 100644 --- a/composer.json +++ b/composer.json @@ -46,6 +46,7 @@ "codewithdennis/filament-select-tree": "^4.0", "filament/filament": "^4.0", "nette/php-generator": "^4.1", + "phiki/phiki": "^2.0", "saade/filament-adjacency-list": "^4.0", "spatie/laravel-package-tools": "^1.18", "spatie/once": "^3.1", @@ -56,7 +57,7 @@ "laravel/pint": "^1.14", "nunomaduro/collision": "^8.1.1||^7.10.0", "larastan/larastan": "^3.7", - "orchestra/testbench": "^9.0.0||^8.22.0", + "orchestra/testbench": "^10.0", "pestphp/pest": "^4.1", "pestphp/pest-plugin-arch": "^4.0", "pestphp/pest-plugin-laravel": "^4.0", @@ -73,6 +74,7 @@ "Backstage\\Fields\\": "packages/fields/src/", "Backstage\\Fields\\Database\\Factories\\": "packages/fields/database/factories/", "Backstage\\Media\\": "packages/media/src/", + "Backstage\\UploadcareField\\": "packages/uploadcare-field/src/", "Backstage\\Database\\Factories\\": "database/factories/", "Backstage\\Database\\Seeders\\": "database/seeders/" }, @@ -82,7 +84,8 @@ }, "autoload-dev": { "psr-4": { - "Backstage\\Tests\\": "tests/" + "Backstage\\Tests\\": "tests/", + "Backstage\\UploadcareField\\Tests\\": "packages/uploadcare-field/tests/" } }, "scripts": { @@ -124,4 +127,4 @@ ], "minimum-stability": "dev", "prefer-stable": true -} \ No newline at end of file +} diff --git a/config/backstage/media.php b/config/backstage/media.php new file mode 100644 index 00000000..13749395 --- /dev/null +++ b/config/backstage/media.php @@ -0,0 +1,73 @@ + [ + 'image/jpeg', + 'image/png', + 'image/webp', + 'image/svg+xml', + 'video/mp4', + 'video/webm', + 'audio/mpeg', + 'audio/ogg', + 'application/pdf', + ], + + 'directory' => 'media', + + 'disk' => config('filament.filesystem_disk', 'public'), + + 'should_preserve_filenames' => false, + + 'should_register_navigation' => true, + + 'visibility' => 'public', + + /* + |-------------------------------------------------------------------------- + | Tenancy + |-------------------------------------------------------------------------- + | + */ + 'is_tenant_aware' => true, + 'tenant_ownership_relationship_name' => 'site', + 'tenant_relationship' => 'site', + 'tenant_model' => Site::class, + + /* + |-------------------------------------------------------------------------- + | Model and resource + |-------------------------------------------------------------------------- + | + */ + 'model' => \Backstage\Media\Models\Media::class, + + 'user_model' => User::class, + + 'resources' => [ + 'label' => 'Media', + 'plural_label' => 'Media', + 'navigation_group' => null, + 'navigation_label' => 'Media', + 'navigation_icon' => 'heroicon-o-photo', + 'navigation_sort' => null, + 'navigation_count_badge' => false, + 'resource' => \Backstage\Media\Resources\MediaResource::class, + ], + + 'file_upload' => [ + 'models' => [ + Content::class, + ], + ], +]; diff --git a/database/migrations/2025_02_15_123430_create_media_relationships_table.php b/database/migrations/2025_02_15_123430_create_media_relationships_table.php index e7194908..f537b980 100644 --- a/database/migrations/2025_02_15_123430_create_media_relationships_table.php +++ b/database/migrations/2025_02_15_123430_create_media_relationships_table.php @@ -21,8 +21,10 @@ public function up(): void ->on(app(config('backstage.media.model', \Backstage\Media\Models\Media::class))->getTable()) ->cascadeOnDelete(); - // Polymorphic model relationship - $table->morphs('model'); + // Polymorphic model relationship (String ID support) + $table->string('model_type'); + $table->string('model_id', 36); + $table->index(['model_type', 'model_id']); // Optional position for each relationship $table->unsignedInteger('position')->nullable(); diff --git a/database/migrations/2025_11_06_120044_create_translated_attributes_table.php b/database/migrations/2025_11_06_120044_create_translated_attributes_table.php new file mode 100644 index 00000000..c20965a9 --- /dev/null +++ b/database/migrations/2025_11_06_120044_create_translated_attributes_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('code', 5); + + $table->foreign('code') + ->references('code') + ->on('languages') + ->onDelete('cascade'); + + $table->ulidMorphs('translatable'); + + $table->longText('attribute'); + $table->longText('translated_attribute')->nullable(); + $table->timestamp('translated_at')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + }); + } + + public function down() + { + Schema::dropIfExists('translated_attributes'); + } +}; diff --git a/database/migrations/2025_11_06_120623_add_alt_column_to_media_table.php b/database/migrations/2025_11_06_120623_add_alt_column_to_media_table.php new file mode 100644 index 00000000..8e943428 --- /dev/null +++ b/database/migrations/2025_11_06_120623_add_alt_column_to_media_table.php @@ -0,0 +1,24 @@ +getTable(), function (Blueprint $table) { + $table->text('alt')->nullable()->after('height'); + }); + } + + public function down(): void + { + $model = config('backstage.media.model'); + Schema::table((new $model)->getTable(), function (Blueprint $table) { + $table->dropColumn('alt'); + }); + } +}; diff --git a/database/seeders/BackstageSeeder.php b/database/seeders/BackstageSeeder.php index e23fc063..f66e65de 100644 --- a/database/seeders/BackstageSeeder.php +++ b/database/seeders/BackstageSeeder.php @@ -12,7 +12,6 @@ use Backstage\Models\Language; use Backstage\Models\Site; use Backstage\Models\Type; -use Backstage\Models\User; use Illuminate\Database\Seeder; use Illuminate\Support\Str; @@ -173,47 +172,5 @@ public function run(): void (string) Str::uuid() => ['type' => 'form', 'data' => ['slug' => 'contact']], ]), ]), 'values')->create(); - - User::factory([ - 'name' => 'Mark', - 'email' => 'mark@vk10.nl', - 'password' => 'mark@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Rob', - 'email' => 'rob@vk10.nl', - 'password' => 'rob@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Mathieu', - 'email' => 'mathieu@vk10.nl', - 'password' => 'mathieu@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Bas', - 'email' => 'bas@vk10.nl', - 'password' => 'bas@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Yoni', - 'email' => 'yoni@vk10.nl', - 'password' => 'yoni@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Patrick', - 'email' => 'patrick@vk10.nl', - 'password' => 'patrick@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Sandro', - 'email' => 'sandro@vk10.nl', - 'password' => 'sandro@vk10.nl', - ])->create(); } } diff --git a/packages/core/config/backstage/cms.php b/packages/core/config/backstage/cms.php index 4b1001c9..9578e907 100644 --- a/packages/core/config/backstage/cms.php +++ b/packages/core/config/backstage/cms.php @@ -22,7 +22,7 @@ Backstage\Resources\SettingResource::class, Backstage\Resources\SiteResource::class, Backstage\Resources\TagResource::class, - Backstage\Media\Resources\MediaResource::class, + // Backstage\Resources\MediaResource::class, // Backstage\Resources\TemplateResource::class, Backstage\Resources\TypeResource::class, Backstage\Resources\UserResource::class, diff --git a/packages/core/database/migrations/2025_02_15_123430_create_media_relationships_table.php b/packages/core/database/migrations/2025_02_15_123430_create_media_relationships_table.php index e7194908..f537b980 100644 --- a/packages/core/database/migrations/2025_02_15_123430_create_media_relationships_table.php +++ b/packages/core/database/migrations/2025_02_15_123430_create_media_relationships_table.php @@ -21,8 +21,10 @@ public function up(): void ->on(app(config('backstage.media.model', \Backstage\Media\Models\Media::class))->getTable()) ->cascadeOnDelete(); - // Polymorphic model relationship - $table->morphs('model'); + // Polymorphic model relationship (String ID support) + $table->string('model_type'); + $table->string('model_id', 36); + $table->index(['model_type', 'model_id']); // Optional position for each relationship $table->unsignedInteger('position')->nullable(); diff --git a/packages/core/database/migrations/2025_11_06_120044_create_translated_attributes_table.php b/packages/core/database/migrations/2025_11_06_120044_create_translated_attributes_table.php new file mode 100644 index 00000000..8b112883 --- /dev/null +++ b/packages/core/database/migrations/2025_11_06_120044_create_translated_attributes_table.php @@ -0,0 +1,39 @@ +id(); + $table->string('code', 5); + + $table->foreign('code') + ->references('code') + ->on('languages') + ->onDelete('cascade'); + + $table->ulidMorphs('translatable'); + + $table->longText('attribute'); + $table->longText('translated_attribute')->nullable(); + $table->timestamp('translated_at')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + }); + } + + public function down() + { + Schema::dropIfExists('translated_attributes'); + } +}; diff --git a/packages/core/database/migrations/2025_11_06_120623_add_alt_column_to_media_table.php b/packages/core/database/migrations/2025_11_06_120623_add_alt_column_to_media_table.php new file mode 100644 index 00000000..8e943428 --- /dev/null +++ b/packages/core/database/migrations/2025_11_06_120623_add_alt_column_to_media_table.php @@ -0,0 +1,24 @@ +getTable(), function (Blueprint $table) { + $table->text('alt')->nullable()->after('height'); + }); + } + + public function down(): void + { + $model = config('backstage.media.model'); + Schema::table((new $model)->getTable(), function (Blueprint $table) { + $table->dropColumn('alt'); + }); + } +}; diff --git a/packages/core/database/migrations/2025_12_08_000000_make_media_relationships_model_id_string.php b/packages/core/database/migrations/2025_12_08_000000_make_media_relationships_model_id_string.php new file mode 100644 index 00000000..5173344e --- /dev/null +++ b/packages/core/database/migrations/2025_12_08_000000_make_media_relationships_model_id_string.php @@ -0,0 +1,25 @@ +string('model_id', 36)->change(); + $table->string('model_type')->change(); + }); + } + + public function down(): void + { + Schema::table('media_relationships', function (Blueprint $table) { + // Revert to typical big integer if needed (unsafe if data exists) + // $table->unsignedBigInteger('model_id')->change(); + }); + } +}; diff --git a/packages/core/database/migrations/2025_12_10_080000_update_media_relationships_indexes.php b/packages/core/database/migrations/2025_12_10_080000_update_media_relationships_indexes.php new file mode 100644 index 00000000..f94f0cf0 --- /dev/null +++ b/packages/core/database/migrations/2025_12_10_080000_update_media_relationships_indexes.php @@ -0,0 +1,63 @@ +dropForeign(['media_ulid']); + }); + } catch (\Illuminate\Database\QueryException $e) { + // Ignore if foreign key does not exist + } + + // 2. Try to drop unique index (might fail if already dropped) + try { + Schema::table('media_relationships', function (Blueprint $table) { + $table->dropUnique(['media_ulid', 'model_type', 'model_id']); + }); + } catch (\Illuminate\Database\QueryException $e) { + // Ignore if index does not exist + } + + // 3. Try to add new index (might fail if already exists) + try { + Schema::table('media_relationships', function (Blueprint $table) { + $table->index(['model_type', 'model_id', 'position']); + }); + } catch (\Illuminate\Database\QueryException $e) { + // Ignore if index already exists + } + + // 4. Re-add foreign key (using safe 'foreign' method) + Schema::table('media_relationships', function (Blueprint $table) { + // We use a separate call here to ensure we don't catch unexpected errors in the definition + // But we might want to check if it exists? + // Generically adding a FK usually fails if it exists with same name. + // Since we know we tried to drop it in step 1, this should be safe unless step 1 failed unrelatedly. + // However, to be extra safe against "Constraint already exists": + try { + $table->foreign('media_ulid') + ->references('ulid') + ->on(app(config('backstage.media.model', \Backstage\Media\Models\Media::class))->getTable()) + ->cascadeOnDelete(); + } catch (\Illuminate\Database\QueryException $e) { + // assume it exists if it fails + } + }); + } + + public function down(): void + { + Schema::table('media_relationships', function (Blueprint $table) { + $table->dropIndex(['model_type', 'model_id', 'position']); + $table->unique(['media_ulid', 'model_type', 'model_id']); + }); + } +}; diff --git a/packages/core/database/migrations/2025_12_10_080001_update_translatable_column.php b/packages/core/database/migrations/2025_12_10_080001_update_translatable_column.php new file mode 100644 index 00000000..3638e863 --- /dev/null +++ b/packages/core/database/migrations/2025_12_10_080001_update_translatable_column.php @@ -0,0 +1,21 @@ +string('translatable_id', 36)->change(); + $table->string('translatable_type', 36)->change(); + }); + } + + public function down() + { + Schema::dropIfExists('translated_attributes'); + } +}; diff --git a/packages/core/database/seeders/BackstageSeeder.php b/packages/core/database/seeders/BackstageSeeder.php index e23fc063..f66e65de 100644 --- a/packages/core/database/seeders/BackstageSeeder.php +++ b/packages/core/database/seeders/BackstageSeeder.php @@ -12,7 +12,6 @@ use Backstage\Models\Language; use Backstage\Models\Site; use Backstage\Models\Type; -use Backstage\Models\User; use Illuminate\Database\Seeder; use Illuminate\Support\Str; @@ -173,47 +172,5 @@ public function run(): void (string) Str::uuid() => ['type' => 'form', 'data' => ['slug' => 'contact']], ]), ]), 'values')->create(); - - User::factory([ - 'name' => 'Mark', - 'email' => 'mark@vk10.nl', - 'password' => 'mark@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Rob', - 'email' => 'rob@vk10.nl', - 'password' => 'rob@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Mathieu', - 'email' => 'mathieu@vk10.nl', - 'password' => 'mathieu@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Bas', - 'email' => 'bas@vk10.nl', - 'password' => 'bas@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Yoni', - 'email' => 'yoni@vk10.nl', - 'password' => 'yoni@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Patrick', - 'email' => 'patrick@vk10.nl', - 'password' => 'patrick@vk10.nl', - ])->create(); - - User::factory([ - 'name' => 'Sandro', - 'email' => 'sandro@vk10.nl', - 'password' => 'sandro@vk10.nl', - ])->create(); } } diff --git a/packages/core/resources/views/components/page.blade.php b/packages/core/resources/views/components/page.blade.php index 745cbbde..da122ed7 100644 --- a/packages/core/resources/views/components/page.blade.php +++ b/packages/core/resources/views/components/page.blade.php @@ -5,7 +5,7 @@