From 5b979dafb79179dbd2a38dcae3b89c2541131056 Mon Sep 17 00:00:00 2001 From: prplwtf Date: Sun, 10 May 2026 19:39:03 +0200 Subject: [PATCH 1/9] feat: start work on remote metadata (i hope im doing this right) --- .../MetadataCacheCommand.php | 47 +++++++++++++++++++ .../BlueprintFramework/CachedMetadata.php | 27 +++++++++++ ...create_extension_cached_metadata_table.php | 26 ++++++++++ 3 files changed, 100 insertions(+) create mode 100644 app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php create mode 100644 app/Models/BlueprintFramework/CachedMetadata.php create mode 100644 database/migrations/2026_05_10_174849_create_extension_cached_metadata_table.php diff --git a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php new file mode 100644 index 00000000..ace5fa64 --- /dev/null +++ b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php @@ -0,0 +1,47 @@ +blueprint->extensions(); + + // get version info + $context = stream_context_create(['http' => ['method' => 'GET', 'header' => 'User-Agent: BlueprintFramework']]); + $remote_versions = @file_get_contents( + $this->PlaceholderService->api_url() . '/api/extensions/latest', + false, + $context + ); + + if($remote_versions) { + + } + } +} diff --git a/app/Models/BlueprintFramework/CachedMetadata.php b/app/Models/BlueprintFramework/CachedMetadata.php new file mode 100644 index 00000000..c2914795 --- /dev/null +++ b/app/Models/BlueprintFramework/CachedMetadata.php @@ -0,0 +1,27 @@ + 'array', + 'fetched_at' => 'datetime', + ]; + protected $fillable = ['identifier', 'metadata', 'fetched_at']; + + /** + * Return the latest_version string for a given extension identifier, or null if not found. + */ + public static function latestVersionFor(string $identifier): ?string + { + $row = static::where('identifier', $identifier)->first(['metadata']); + + if (! $row) { + return null; + } + + return $row->metadata['latest_version'] ?? null; + } +} diff --git a/database/migrations/2026_05_10_174849_create_extension_cached_metadata_table.php b/database/migrations/2026_05_10_174849_create_extension_cached_metadata_table.php new file mode 100644 index 00000000..9fdbafc6 --- /dev/null +++ b/database/migrations/2026_05_10_174849_create_extension_cached_metadata_table.php @@ -0,0 +1,26 @@ +id(); + $table->string('identifier')->unique(); // the extensions' identifier + $table->json('metadata'); // the metadata related to the extension + $table->timestamp('fetched_at')->nullable(); // last time blueprint fetched ts + $table->timestamps(); + + $table->index(['fetched_at']); + }); + } + + public function down(): void + { + Schema::dropIfExists('extension_cached_metadata'); + } +}; From 19a45cfd005bd386ac6c85549b7312e1119efd82 Mon Sep 17 00:00:00 2001 From: prplwtf Date: Sun, 10 May 2026 20:40:49 +0200 Subject: [PATCH 2/9] feat: progress?? actually store the stuff in the database --- .../MetadataCacheCommand.php | 46 +++++++++++++++++-- .../BlueprintFramework/CachedMetadata.php | 27 ----------- app/Models/ExtensionCachedMetadata.php | 26 +++++++++++ 3 files changed, 68 insertions(+), 31 deletions(-) delete mode 100644 app/Models/BlueprintFramework/CachedMetadata.php create mode 100644 app/Models/ExtensionCachedMetadata.php diff --git a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php index ace5fa64..f332f8e7 100644 --- a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php +++ b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php @@ -12,6 +12,9 @@ namespace Pterodactyl\Console\Commands\BlueprintFramework; use Illuminate\Console\Command; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; +use Pterodactyl\Models\ExtensionCachedMetadata; use Pterodactyl\BlueprintFramework\Services\PlaceholderService\BlueprintPlaceholderService; use Pterodactyl\BlueprintFramework\Libraries\ExtensionLibrary\Console\BlueprintConsoleLibrary as BlueprintExtensionLibrary; @@ -29,19 +32,54 @@ public function __construct( public function handle() { - // figure out which extensions are currently installed - $installed_extensions = $this->blueprint->extensions(); + $now = now(); + $rows = []; + $installedExtensions = $this->blueprint->extensions(); // get version info $context = stream_context_create(['http' => ['method' => 'GET', 'header' => 'User-Agent: BlueprintFramework']]); - $remote_versions = @file_get_contents( + $remoteVersions = @file_get_contents( $this->PlaceholderService->api_url() . '/api/extensions/latest', false, $context ); - if($remote_versions) { + if($remoteVersions) { + $remoteVersionsData = json_decode($remoteVersions, true); + } + + if(! isset($remoteVersionsData)) { + $this->error('failed to fetch extension versions'); + return false; + } + foreach ($installedExtensions as $identifier) { + if(! isset($remoteVersionsData[$identifier]) || ! is_scalar($remoteVersionsData[$identifier])) continue; + $rows[] = [ + 'identifier' => $identifier, + 'metadata' => json_encode(['latest_version' => (string) $remoteVersionsData[$identifier]]), + 'fetched_at' => $now, + ]; } + + if (empty($rows)) { + $this->info('no relevant data available, do you have any extensions installed?'); + return false; + } + + $table = (new ExtensionCachedMetadata())->getTable(); + $temp = $table . '_tmp_' . substr(uniqid(), -8); + + DB::statement("CREATE TABLE {$temp} LIKE {$table}"); + + foreach (array_chunk($rows, 500) as $chunk) { + DB::table($temp)->insert($chunk); + } + + // atomic swap + DB::statement("RENAME TABLE {$table} TO {$table}_bak, {$temp} TO {$table}"); + DB::statement("DROP TABLE {$table}_bak"); + + $this->info('updated extension cached metadata'); } } diff --git a/app/Models/BlueprintFramework/CachedMetadata.php b/app/Models/BlueprintFramework/CachedMetadata.php deleted file mode 100644 index c2914795..00000000 --- a/app/Models/BlueprintFramework/CachedMetadata.php +++ /dev/null @@ -1,27 +0,0 @@ - 'array', - 'fetched_at' => 'datetime', - ]; - protected $fillable = ['identifier', 'metadata', 'fetched_at']; - - /** - * Return the latest_version string for a given extension identifier, or null if not found. - */ - public static function latestVersionFor(string $identifier): ?string - { - $row = static::where('identifier', $identifier)->first(['metadata']); - - if (! $row) { - return null; - } - - return $row->metadata['latest_version'] ?? null; - } -} diff --git a/app/Models/ExtensionCachedMetadata.php b/app/Models/ExtensionCachedMetadata.php new file mode 100644 index 00000000..cfc0e9c4 --- /dev/null +++ b/app/Models/ExtensionCachedMetadata.php @@ -0,0 +1,26 @@ + 'array', + 'fetched_at' => 'datetime', + ]; + protected $fillable = ['identifier', 'metadata', 'fetched_at']; + public $timestamps = true; + + // return the latest_version for a given extension identifier, or null if not found + public static function latestVersionFor(string $identifier): ?string + { + $row = static::where('identifier', $identifier)->first(['metadata']); + + if (! $row) { + return null; + } + + return $row->metadata['latest_version'] ?? null; + } +} From 6af004994c917d316f7da34fd825f742699288e0 Mon Sep 17 00:00:00 2001 From: prplwtf Date: Sun, 10 May 2026 20:51:07 +0200 Subject: [PATCH 3/9] feat: schedule meta command --- .../BlueprintFramework/MetadataCacheCommand.php | 1 - app/Console/Kernel.php | 8 +++++++- .../Controllers/Admin/ExtensionsController.php | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php index f332f8e7..7b545e9f 100644 --- a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php +++ b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php @@ -13,7 +13,6 @@ use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Facades\Log; use Pterodactyl\Models\ExtensionCachedMetadata; use Pterodactyl\BlueprintFramework\Services\PlaceholderService\BlueprintPlaceholderService; use Pterodactyl\BlueprintFramework\Libraries\ExtensionLibrary\Console\BlueprintConsoleLibrary as BlueprintExtensionLibrary; diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 34ff43a5..fad9a76e 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -54,6 +54,10 @@ protected function schedule(Schedule $schedule): void $this->registerTelemetry($schedule); } + // ============================ + // BLUEPRINT SCHEDULES + // ============================ + // Blueprint telemetry $blueprint = app()->make(BlueprintExtensionLibrary::class); if ($blueprint->dbGet('blueprint', 'flags:telemetry_enabled', 0)) { @@ -62,7 +66,9 @@ protected function schedule(Schedule $schedule): void } // Blueprint-related utilities - $schedule->command('bp:version:cache')->dailyAt(str_pad(rand(0, 23), 2, '0', STR_PAD_LEFT) . ':' . str_pad(rand(0, 59), 2, '0', STR_PAD_LEFT)); + $randTime = str_pad(rand(0, 23), 2, '0', STR_PAD_LEFT) . ':' . str_pad(rand(0, 59), 2, '0', STR_PAD_LEFT); + $schedule->command('bp:version:cache')->dailyAt($randTime); + $schedule->command('bp:meta')->dailyAt($randTime); // Blueprint extension schedules GetExtensionSchedules::schedules($schedule); diff --git a/app/Http/Controllers/Admin/ExtensionsController.php b/app/Http/Controllers/Admin/ExtensionsController.php index 694d50d4..165691af 100644 --- a/app/Http/Controllers/Admin/ExtensionsController.php +++ b/app/Http/Controllers/Admin/ExtensionsController.php @@ -2,14 +2,15 @@ namespace Pterodactyl\Http\Controllers\Admin; -use Illuminate\Support\Facades\Artisan; use Illuminate\View\View; +use Database\Seeders\BlueprintSeeder; +use Illuminate\Support\Facades\Artisan; use Illuminate\View\Factory as ViewFactory; use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Models\ExtensionCachedMetadata; use Pterodactyl\Services\Helpers\SoftwareVersionService; use Pterodactyl\BlueprintFramework\Services\PlaceholderService\BlueprintPlaceholderService; use Pterodactyl\BlueprintFramework\Libraries\ExtensionLibrary\Admin\BlueprintAdminLibrary as BlueprintExtensionLibrary; -use Database\Seeders\BlueprintSeeder; class ExtensionsController extends Controller { @@ -32,7 +33,7 @@ public function index(): View { $configuration = $this->blueprint->dbGetMany('blueprint'); $defaults = []; - + if (($configuration['internal:version:latest'] ?? false) === false) { Artisan::call('bp:version:cache'); $latestBlueprintVersion = $this->blueprint->dbGet('blueprint', 'internal:version:latest'); @@ -47,6 +48,12 @@ public function index(): View } } + $metadata = ExtensionCachedMetadata::whereIn('identifier', $this->blueprint->extensions()) + ->get() + ->keyBy('identifier') + ->map(fn($m) => $m->metadata) + ->toArray(); + return $this->view->make('admin.extensions', [ 'blueprint' => $this->blueprint, 'PlaceholderService' => $this->PlaceholderService, @@ -54,7 +61,8 @@ public function index(): View 'latestBlueprintVersion' => $latestBlueprintVersion, 'defaults' => $defaults, 'seeder' => $this->seeder, - + 'metadata' => $metadata, + 'version' => $this->version, 'root' => "/admin/extensions", ]); From 027273b55812bc95e04a0905ca188e7065640d88 Mon Sep 17 00:00:00 2001 From: prplwtf Date: Sun, 10 May 2026 22:07:26 +0200 Subject: [PATCH 4/9] feat: add extension version update thing to button --- .../MetadataCacheCommand.php | 13 +++++++++- .../BlueprintExtensionController.php | 23 +++++++++++------- .../blueprint/assets/blueprint.style.css | 18 ++++++++++---- database/Seeders/BlueprintSeeder.php | 5 ++++ resources/views/admin/extensions.blade.php | 3 ++- .../views/blueprint/admin/admin.blade.php | 2 +- .../views/blueprint/admin/entry.blade.php | 24 +++++++++++++++++-- 7 files changed, 71 insertions(+), 17 deletions(-) diff --git a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php index 7b545e9f..08b3bfca 100644 --- a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php +++ b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php @@ -31,6 +31,11 @@ public function __construct( public function handle() { + if(! $this->blueprint->dbGet("blueprint", "flags:remote_metadata")) { + $this->error('remote_metadata flag set to false'); + return false; + } + $now = now(); $rows = []; $installedExtensions = $this->blueprint->extensions(); @@ -54,9 +59,15 @@ public function handle() foreach ($installedExtensions as $identifier) { if(! isset($remoteVersionsData[$identifier]) || ! is_scalar($remoteVersionsData[$identifier])) continue; + + $local_extension = $this->blueprint->extensionConfig($identifier); + $rows[] = [ 'identifier' => $identifier, - 'metadata' => json_encode(['latest_version' => (string) $remoteVersionsData[$identifier]]), + 'metadata' => json_encode([ + 'latest_version' => (string) $remoteVersionsData[$identifier], + 'local_version' => (string) $local_extension['info']['version'] | '', + ]), 'fetched_at' => $now, ]; } diff --git a/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php b/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php index e8b48044..0995ea6f 100644 --- a/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php +++ b/app/Http/Controllers/Admin/Extensions/Blueprint/BlueprintExtensionController.php @@ -2,13 +2,13 @@ namespace Pterodactyl\Http\Controllers\Admin\Extensions\Blueprint; -use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface; use Illuminate\Http\RedirectResponse; -use Pterodactyl\Http\Requests\Admin\AdminFormRequest; use Database\Seeders\BlueprintSeeder; +use Illuminate\Support\Facades\Artisan; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Http\Requests\Admin\AdminFormRequest; +use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface; -// FIXME: Move form request and remove controller. class BlueprintExtensionController extends Controller { @@ -26,10 +26,17 @@ public function __construct( */ public function update(BlueprintAdminFormRequest $request): RedirectResponse { + $meta_flag = $this->settings->get('blueprint::flags:remote_metadata'); + foreach ($request->validated() as $key => $value) { $this->settings->set('blueprint::' . $key, $value); } + // refresh meta if the flag has been altered + if($meta_flag != $request->validated()['flags:remote_metadata']) { + Artisan::call('bp:meta'); + } + return redirect()->route('admin.extensions'); } } @@ -41,11 +48,11 @@ public function rules(): array // Get schema to determine types $seeder = app(BlueprintSeeder::class); $schema = $seeder->getSchema(); - + $rules = []; foreach ($schema['flags'] as $key => $config) { $flagPath = "flags:{$key}"; - + // Build validation rules based on type switch ($config['type']) { case 'boolean': @@ -62,7 +69,7 @@ public function rules(): array break; } } - + return $rules; } -} \ No newline at end of file +} diff --git a/blueprint/extensions/blueprint/assets/blueprint.style.css b/blueprint/extensions/blueprint/assets/blueprint.style.css index e4cb0060..665c4c04 100644 --- a/blueprint/extensions/blueprint/assets/blueprint.style.css +++ b/blueprint/extensions/blueprint/assets/blueprint.style.css @@ -111,7 +111,18 @@ tag[blue] {background-color:#288afb;} width: calc( 100% - 15px ); overflow: clip; text-overflow: ellipsis; - opacity: .6; +} +.extension-btn-update { + background-color: #194323; + color: #3dd15f !important; + border: 1px solid #265f33; + font-weight: 700; + border-radius: 12px; + padding: 0 8px; + display: inline-flex; + flex-direction: row; + gap: 5px; + margin-left: 5px; } .extension-btn { background-color:#1f2933; @@ -120,7 +131,6 @@ tag[blue] {background-color:#288afb;} height:calc(65px + 14px); padding: 0px !important; overflow:hidden; - vertical-align:center; transition:background-color .2s; border-radius:8px; } @@ -169,9 +179,9 @@ tag[blue] {background-color:#288afb;} margin-left: -7px; border-width: 7px; border-style: solid; - border-color: + border-color: transparent transparent #1f2933 transparent; -} \ No newline at end of file +} diff --git a/database/Seeders/BlueprintSeeder.php b/database/Seeders/BlueprintSeeder.php index bc28defe..f913b94d 100644 --- a/database/Seeders/BlueprintSeeder.php +++ b/database/Seeders/BlueprintSeeder.php @@ -45,6 +45,11 @@ class BlueprintSeeder extends Seeder 'type' => 'boolean', 'hidden' => false, ], + 'remote_metadata' => [ + 'default' => true, + 'type' => 'boolean', + 'hidden' => false, + ], 'show_in_sidebar' => [ 'default' => false, 'type' => 'boolean', diff --git a/resources/views/admin/extensions.blade.php b/resources/views/admin/extensions.blade.php index fa63d1e3..fe8fe3c4 100644 --- a/resources/views/admin/extensions.blade.php +++ b/resources/views/admin/extensions.blade.php @@ -131,7 +131,7 @@ logo logo

Blueprint

-

+

system @@ -148,6 +148,7 @@ 'EXTENSION_ID' => $extension['identifier'], 'EXTENSION_NAME' => $extension['name'], 'EXTENSION_VERSION' => $extension['version'], + 'EXTENSION_METADATA' => $metadata[$extension['identifier']], 'EXTENSION_ICON' => !empty($extension['icon']) ? '/assets/extensions/'.$extension['identifier'].'/icon.'.pathinfo($extension['icon'], PATHINFO_EXTENSION) : '/assets/extensions/'.$extension['identifier'].'/icon.jpg' diff --git a/resources/views/blueprint/admin/admin.blade.php b/resources/views/blueprint/admin/admin.blade.php index a7efe441..0f6fbb07 100644 --- a/resources/views/blueprint/admin/admin.blade.php +++ b/resources/views/blueprint/admin/admin.blade.php @@ -12,7 +12,7 @@ @endsection @section("blueprint.import") - {!! $blueprint->importStylesheet('https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css') !!} + {!! $blueprint->importStylesheet('https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.css') !!} {!! $blueprint->importStylesheet('/assets/extensions/blueprint/admin.extensions.css') !!} {!! $blueprint->importStylesheet('/assets/extensions/blueprint/blueprint.style.css') !!} @endsection diff --git a/resources/views/blueprint/admin/entry.blade.php b/resources/views/blueprint/admin/entry.blade.php index ab5f3509..247a4e6f 100644 --- a/resources/views/blueprint/admin/entry.blade.php +++ b/resources/views/blueprint/admin/entry.blade.php @@ -1,4 +1,16 @@ @if(isset($EXTENSION_ID)) + @php + $latest = true; + if(isset($EXTENSION_METADATA)) { + if( + $EXTENSION_METADATA['latest_version'] != $EXTENSION_VERSION + && $EXTENSION_METADATA['local_version'] == $EXTENSION_VERSION + ) { + $latest = false; + } + } + @endphp +

-@endif \ No newline at end of file +@endif From 3b3b14ad4a869cb3a4896e76fd4cdd6896135936 Mon Sep 17 00:00:00 2001 From: prplwtf Date: Sun, 10 May 2026 22:25:35 +0200 Subject: [PATCH 5/9] feat: implement extension update reminder --- app/Http/Controllers/Admin/ExtensionsController.php | 13 ++++++++----- .../extensions/blueprint/assets/blueprint.style.css | 6 +++--- resources/views/admin/extensions.blade.php | 10 ++++++++-- resources/views/blueprint/admin/template.blade.php | 5 ++++- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/Admin/ExtensionsController.php b/app/Http/Controllers/Admin/ExtensionsController.php index 165691af..083d8c64 100644 --- a/app/Http/Controllers/Admin/ExtensionsController.php +++ b/app/Http/Controllers/Admin/ExtensionsController.php @@ -48,11 +48,14 @@ public function index(): View } } - $metadata = ExtensionCachedMetadata::whereIn('identifier', $this->blueprint->extensions()) - ->get() - ->keyBy('identifier') - ->map(fn($m) => $m->metadata) - ->toArray(); + $metadata = []; + if($this->blueprint->dbGet('blueprint', 'flags:remote_metadata')) { + $metadata = ExtensionCachedMetadata::whereIn('identifier', $this->blueprint->extensions()) + ->get() + ->keyBy('identifier') + ->map(fn($m) => $m->metadata) + ->toArray(); + } return $this->view->make('admin.extensions', [ 'blueprint' => $this->blueprint, diff --git a/blueprint/extensions/blueprint/assets/blueprint.style.css b/blueprint/extensions/blueprint/assets/blueprint.style.css index 665c4c04..c1a214d4 100644 --- a/blueprint/extensions/blueprint/assets/blueprint.style.css +++ b/blueprint/extensions/blueprint/assets/blueprint.style.css @@ -25,9 +25,9 @@ tag { display:inline-block; - padding:3px; + padding: 3px 5px; background-color:#505050; - border-radius:5px; + border-radius:15px; font-size:12px; color:white; } @@ -36,7 +36,7 @@ tag[mg-right] {margin-right:5px;} tag[red] {background-color:#ff4040;} tag[green] {background-color:#27b949;} tag[blue] {background-color:#288afb;} -[ext-title]{display:flex; flex-direction:row; align-items:center;} +[ext-title]{display:flex; flex-direction:row; align-items: end;} .btn-gray { diff --git a/resources/views/admin/extensions.blade.php b/resources/views/admin/extensions.blade.php index fe8fe3c4..f1138eb0 100644 --- a/resources/views/admin/extensions.blade.php +++ b/resources/views/admin/extensions.blade.php @@ -143,12 +143,18 @@ @foreach($blueprint->extensionsConfigs() as $extension) - + @include("blueprint.admin.entry", [ 'EXTENSION_ID' => $extension['identifier'], 'EXTENSION_NAME' => $extension['name'], 'EXTENSION_VERSION' => $extension['version'], - 'EXTENSION_METADATA' => $metadata[$extension['identifier']], + 'EXTENSION_METADATA' => $metadataScoped, 'EXTENSION_ICON' => !empty($extension['icon']) ? '/assets/extensions/'.$extension['identifier'].'/icon.'.pathinfo($extension['icon'], PATHINFO_EXTENSION) : '/assets/extensions/'.$extension['identifier'].'/icon.jpg' diff --git a/resources/views/blueprint/admin/template.blade.php b/resources/views/blueprint/admin/template.blade.php index fc27feeb..c6b4b78e 100644 --- a/resources/views/blueprint/admin/template.blade.php +++ b/resources/views/blueprint/admin/template.blade.php @@ -13,7 +13,10 @@ @endif -

{{ $EXTENSION_NAME }}{{ $EXTENSION_VERSION }}

+

+ {{ $EXTENSION_NAME }} + {{ $EXTENSION_VERSION }} +

@endsection @section("extension.description") From 3982e9f00b2ebf3f379e2ad77d2ba8a5c638e8e0 Mon Sep 17 00:00:00 2001 From: prplwtf Date: Mon, 11 May 2026 14:34:24 +0200 Subject: [PATCH 6/9] feat: add method to $blueprint --- .../ExtensionLibrary/BlueprintBaseLibrary.php | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php b/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php index 2d3574c4..a5f1d80a 100644 --- a/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php +++ b/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php @@ -14,9 +14,10 @@ namespace Pterodactyl\BlueprintFramework\Libraries\ExtensionLibrary; -use Illuminate\Support\Facades\DB; -use Illuminate\Support\Collection; use Symfony\Component\Yaml\Yaml; +use Illuminate\Support\Collection; +use Illuminate\Support\Facades\DB; +use Pterodactyl\Models\ExtensionCachedMetadata; class BlueprintBaseLibrary { @@ -294,6 +295,39 @@ public function extensionConfig(string $identifier): ?array return $conf; } + /** + * Retrieves the stored metadata for an extension. + * + * This method checks if the given extension has available metadata and, if so, + * returns the metadata. Please note that this metadata may be delayed, and the + * format of which may change, so parse wisely. + * + * Requires the 'remote_metadata' flag to be set to true in Blueprint's settings. + * + * @param string $identifier Extension identifier to retrieve metadata for + * + * @return array|null The metadata array for the extension, or null if not available. + */ + public function extensionMetadata(string $identifier): ?array + { + $metadata = []; + if (!$this->extension($identifier)) { + return null; + } + if($this->blueprint->dbGet('blueprint', 'flags:remote_metadata')) { + $metadata = ExtensionCachedMetadata::whereIn('identifier', $this->blueprint->extensions()) + ->get() + ->keyBy('identifier') + ->map(fn($m) => $m->metadata) + ->toArray(); + + if(isset($metadata[$identifier])) { + return $metadata[$identifier]; + } + } + return null; + } + /** * Returns a Collection containing all installed extensions's configs. * From 1389567dd6a87435ab194d42062a5de5bd467251 Mon Sep 17 00:00:00 2001 From: prplwtf Date: Mon, 11 May 2026 15:26:39 +0200 Subject: [PATCH 7/9] feat: add update reminder to extension pages --- .../ExtensionLibrary/BlueprintBaseLibrary.php | 4 ++-- .../blueprint/assets/blueprint.style.css | 8 ++++++- .../views/blueprint/admin/template.blade.php | 24 +++++++++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php b/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php index a5f1d80a..f817d1ef 100644 --- a/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php +++ b/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php @@ -314,8 +314,8 @@ public function extensionMetadata(string $identifier): ?array if (!$this->extension($identifier)) { return null; } - if($this->blueprint->dbGet('blueprint', 'flags:remote_metadata')) { - $metadata = ExtensionCachedMetadata::whereIn('identifier', $this->blueprint->extensions()) + if($this->dbGet('blueprint', 'flags:remote_metadata')) { + $metadata = ExtensionCachedMetadata::whereIn('identifier', $this->extensions()) ->get() ->keyBy('identifier') ->map(fn($m) => $m->metadata) diff --git a/blueprint/extensions/blueprint/assets/blueprint.style.css b/blueprint/extensions/blueprint/assets/blueprint.style.css index c1a214d4..e4f5ab73 100644 --- a/blueprint/extensions/blueprint/assets/blueprint.style.css +++ b/blueprint/extensions/blueprint/assets/blueprint.style.css @@ -26,7 +26,7 @@ tag { display:inline-block; padding: 3px 5px; - background-color:#505050; + background-color: #4d5b69; border-radius:15px; font-size:12px; color:white; @@ -185,3 +185,9 @@ tag[blue] {background-color:#288afb;} #1f2933 transparent; } + +@media screen and (width <= 600px) { + .blueprint-extension-title-tag-icon { + display: none; + } +} diff --git a/resources/views/blueprint/admin/template.blade.php b/resources/views/blueprint/admin/template.blade.php index c6b4b78e..c8128d71 100644 --- a/resources/views/blueprint/admin/template.blade.php +++ b/resources/views/blueprint/admin/template.blade.php @@ -14,8 +14,28 @@ @endif

- {{ $EXTENSION_NAME }} - {{ $EXTENSION_VERSION }} + {{ $EXTENSION_NAME }} + + {{ $EXTENSION_VERSION }} + + + extensionMetadata($EXTENSION_ID); + if(isset($meta)) { + if( + $meta['latest_version'] != $EXTENSION_VERSION + && $meta['local_version'] == $EXTENSION_VERSION + ) { + $latest = false; + } + } + ?> + @if(!$latest) + + {{ $meta['latest_version'] }} + + @endif

@endsection From fe5e3c8fb444d6993fb9291bd81c24fbe73d9329 Mon Sep 17 00:00:00 2001 From: prplwtf Date: Tue, 12 May 2026 18:15:22 +0200 Subject: [PATCH 8/9] fix: change | to ?? --- .../Commands/BlueprintFramework/MetadataCacheCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php index 08b3bfca..894598de 100644 --- a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php +++ b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php @@ -66,7 +66,7 @@ public function handle() 'identifier' => $identifier, 'metadata' => json_encode([ 'latest_version' => (string) $remoteVersionsData[$identifier], - 'local_version' => (string) $local_extension['info']['version'] | '', + 'local_version' => (string) $local_extension['info']['version'] ?? '', ]), 'fetched_at' => $now, ]; From 4634387c00f7216a05b476ba8a7923c93fd8ae93 Mon Sep 17 00:00:00 2001 From: prplwtf Date: Tue, 12 May 2026 19:49:46 +0200 Subject: [PATCH 9/9] feat: do proper databasing --- .../BlueprintFramework/MetadataCacheCommand.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php index 894598de..b2ee1bb4 100644 --- a/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php +++ b/app/Console/Commands/BlueprintFramework/MetadataCacheCommand.php @@ -78,17 +78,11 @@ public function handle() } $table = (new ExtensionCachedMetadata())->getTable(); - $temp = $table . '_tmp_' . substr(uniqid(), -8); - DB::statement("CREATE TABLE {$temp} LIKE {$table}"); - - foreach (array_chunk($rows, 500) as $chunk) { - DB::table($temp)->insert($chunk); - } - - // atomic swap - DB::statement("RENAME TABLE {$table} TO {$table}_bak, {$temp} TO {$table}"); - DB::statement("DROP TABLE {$table}_bak"); + DB::transaction(function () use ($rows, $table) { + DB::table($table)->delete(); + DB::table($table)->insert($rows); + }); $this->info('updated extension cached metadata'); }