diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index f1cdd2998..3a3e7af1c 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -5,6 +5,7 @@ namespace App\Console\Commands; use App\Enums\ActivityTypes; use App\Enums\ApplicationDeploymentStatus; use App\Jobs\CheckHelperImageJob; +use App\Jobs\PullChangelogFromGitHub; use App\Models\ApplicationDeploymentQueue; use App\Models\Environment; use App\Models\ScheduledDatabaseBackup; @@ -64,6 +65,7 @@ class Init extends Command try { $this->cleanupUnnecessaryDynamicProxyConfiguration(); $this->pullTemplatesFromCDN(); + $this->pullChangelogFromGitHub(); } catch (\Throwable $e) { echo "Could not pull templates from CDN: {$e->getMessage()}\n"; } @@ -74,6 +76,7 @@ class Init extends Command try { $this->cleanupInProgressApplicationDeployments(); $this->pullTemplatesFromCDN(); + $this->pullChangelogFromGitHub(); } catch (\Throwable $e) { echo "Could not pull templates from CDN: {$e->getMessage()}\n"; } @@ -109,6 +112,16 @@ class Init extends Command } } + private function pullChangelogFromGitHub() + { + try { + PullChangelogFromGitHub::dispatch(); + echo "Changelog fetch initiated\n"; + } catch (\Throwable $e) { + echo "Could not fetch changelog from GitHub: {$e->getMessage()}\n"; + } + } + private function optimize() { Artisan::call('optimize:clear'); diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index eda2fca74..6df191bb3 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -6,6 +6,7 @@ use App\Jobs\CheckAndStartSentinelJob; use App\Jobs\CheckForUpdatesJob; use App\Jobs\CheckHelperImageJob; use App\Jobs\CleanupInstanceStuffsJob; +use App\Jobs\PullChangelogFromGitHub; use App\Jobs\PullTemplatesFromCDN; use App\Jobs\RegenerateSslCertJob; use App\Jobs\ScheduledJobManager; @@ -67,6 +68,7 @@ class Kernel extends ConsoleKernel $this->scheduleInstance->command('cleanup:unreachable-servers')->daily()->onOneServer(); $this->scheduleInstance->job(new PullTemplatesFromCDN)->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer(); + $this->scheduleInstance->job(new PullChangelogFromGitHub)->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer(); $this->scheduleInstance->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer(); $this->scheduleUpdates(); diff --git a/app/Jobs/PullChangelogFromGitHub.php b/app/Jobs/PullChangelogFromGitHub.php new file mode 100644 index 000000000..e84766f7f --- /dev/null +++ b/app/Jobs/PullChangelogFromGitHub.php @@ -0,0 +1,110 @@ +onQueue('high'); + } + + public function handle(): void + { + try { + $response = Http::retry(3, 1000) + ->timeout(30) + ->get('https://api.github.com/repos/coollabsio/coolify/releases?per_page=10'); + + if ($response->successful()) { + $releases = $response->json(); + $changelog = $this->transformReleasesToChangelog($releases); + + // Group entries by month and save them + $this->saveChangelogEntries($changelog); + } else { + send_internal_notification('PullChangelogFromGitHub failed with: '.$response->status().' '.$response->body()); + } + } catch (\Throwable $e) { + send_internal_notification('PullChangelogFromGitHub failed with: '.$e->getMessage()); + } + } + + private function transformReleasesToChangelog(array $releases): array + { + $entries = []; + + foreach ($releases as $release) { + // Skip drafts and pre-releases if desired + if ($release['draft']) { + continue; + } + + $publishedAt = Carbon::parse($release['published_at']); + + $entry = [ + 'tag_name' => $release['tag_name'], + 'title' => $release['name'] ?: $release['tag_name'], + 'content' => $release['body'] ?: 'No release notes available.', + 'published_at' => $publishedAt->toISOString(), + ]; + + $entries[] = $entry; + } + + return $entries; + } + + private function saveChangelogEntries(array $entries): void + { + // Create changelogs directory if it doesn't exist + $changelogsDir = base_path('changelogs'); + if (! File::exists($changelogsDir)) { + File::makeDirectory($changelogsDir, 0755, true); + } + + // Group entries by year-month + $groupedEntries = []; + foreach ($entries as $entry) { + $date = Carbon::parse($entry['published_at']); + $monthKey = $date->format('Y-m'); + + if (! isset($groupedEntries[$monthKey])) { + $groupedEntries[$monthKey] = []; + } + + $groupedEntries[$monthKey][] = $entry; + } + + // Save each month's entries to separate files + foreach ($groupedEntries as $month => $monthEntries) { + // Sort entries by published date (newest first) + usort($monthEntries, function ($a, $b) { + return Carbon::parse($b['published_at'])->timestamp - Carbon::parse($a['published_at'])->timestamp; + }); + + $monthData = [ + 'entries' => $monthEntries, + 'last_updated' => now()->toISOString(), + ]; + + $filePath = base_path("changelogs/{$month}.json"); + File::put($filePath, json_encode($monthData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + } + + } +} diff --git a/app/Livewire/SettingsDropdown.php b/app/Livewire/SettingsDropdown.php index 5bb3e37a4..314957462 100644 --- a/app/Livewire/SettingsDropdown.php +++ b/app/Livewire/SettingsDropdown.php @@ -2,6 +2,7 @@ namespace App\Livewire; +use App\Jobs\PullChangelogFromGitHub; use App\Services\ChangelogService; use Illuminate\Support\Facades\Auth; use Livewire\Component; @@ -42,6 +43,20 @@ class SettingsDropdown extends Component app(ChangelogService::class)->markAllAsReadForUser(Auth::user()); } + public function manualFetchChangelog() + { + if (! isDev()) { + return; + } + + try { + PullChangelogFromGitHub::dispatch(); + $this->dispatch('success', 'Changelog fetch initiated! Check back in a few moments.'); + } catch (\Throwable $e) { + $this->dispatch('error', 'Failed to fetch changelog: '.$e->getMessage()); + } + } + public function render() { return view('livewire.settings-dropdown', [ diff --git a/app/Livewire/Subscription/Index.php b/app/Livewire/Subscription/Index.php index 8a9cc456f..ac37cca05 100644 --- a/app/Livewire/Subscription/Index.php +++ b/app/Livewire/Subscription/Index.php @@ -75,7 +75,7 @@ class Index extends Component } } catch (\Exception $e) { // Log the error - logger()->error('Stripe API error: ' . $e->getMessage()); + logger()->error('Stripe API error: '.$e->getMessage()); // Set a flag to show an error message to the user $this->addError('stripe', 'Could not retrieve subscription information. Please try again later.'); } finally { diff --git a/app/Models/UserChangelogRead.php b/app/Models/UserChangelogRead.php index 28c384cb5..8c29ece14 100644 --- a/app/Models/UserChangelogRead.php +++ b/app/Models/UserChangelogRead.php @@ -9,7 +9,7 @@ class UserChangelogRead extends Model { protected $fillable = [ 'user_id', - 'changelog_identifier', + 'release_tag', 'read_at', ]; @@ -26,7 +26,7 @@ class UserChangelogRead extends Model { self::firstOrCreate([ 'user_id' => $userId, - 'changelog_identifier' => $identifier, + 'release_tag' => $identifier, ], [ 'read_at' => now(), ]); @@ -35,14 +35,14 @@ class UserChangelogRead extends Model public static function isReadByUser(int $userId, string $identifier): bool { return self::where('user_id', $userId) - ->where('changelog_identifier', $identifier) + ->where('release_tag', $identifier) ->exists(); } public static function getReadIdentifiersForUser(int $userId): array { return self::where('user_id', $userId) - ->pluck('changelog_identifier') + ->pluck('release_tag') ->toArray(); } } diff --git a/app/Services/ChangelogService.php b/app/Services/ChangelogService.php index c6f4c8752..f0887c11c 100644 --- a/app/Services/ChangelogService.php +++ b/app/Services/ChangelogService.php @@ -8,6 +8,7 @@ use Carbon\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; +use Spatie\LaravelMarkdown\MarkdownRenderer; class ChangelogService { @@ -63,7 +64,7 @@ class ChangelogService $readIdentifiers = UserChangelogRead::getReadIdentifiersForUser($user->id); return $entries->map(function ($entry) use ($readIdentifiers) { - $entry->is_read = in_array($entry->version, $readIdentifiers); + $entry->is_read = in_array($entry->tag_name, $readIdentifiers); return $entry; })->sortBy([ @@ -78,7 +79,7 @@ class ChangelogService $entries = $this->getEntries(); $readIdentifiers = UserChangelogRead::getReadIdentifiersForUser($user->id); - return $entries->reject(fn ($entry) => in_array($entry->version, $readIdentifiers))->count(); + return $entries->reject(fn ($entry) => in_array($entry->tag_name, $readIdentifiers))->count(); } else { return Cache::remember( 'user_unread_changelog_count_'.$user->id, @@ -87,7 +88,7 @@ class ChangelogService $entries = $this->getEntries(); $readIdentifiers = UserChangelogRead::getReadIdentifiersForUser($user->id); - return $entries->reject(fn ($entry) => in_array($entry->version, $readIdentifiers))->count(); + return $entries->reject(fn ($entry) => in_array($entry->tag_name, $readIdentifiers))->count(); } ); } @@ -200,7 +201,7 @@ class ChangelogService $entries = $this->getEntries(); foreach ($entries as $entry) { - UserChangelogRead::markAsRead($user->id, $entry->version); + UserChangelogRead::markAsRead($user->id, $entry->tag_name); } Cache::forget('user_unread_changelog_count_'.$user->id); @@ -208,7 +209,7 @@ class ChangelogService private function validateEntryData(array $data): bool { - $required = ['version', 'title', 'content', 'published_at']; + $required = ['tag_name', 'title', 'content', 'published_at']; foreach ($required as $field) { if (! isset($data[$field]) || empty($data[$field])) { @@ -253,41 +254,46 @@ class ChangelogService private function parseMarkdown(string $content): string { - // Convert markdown to HTML using simple regex patterns - $html = $content; + $renderer = app(MarkdownRenderer::class); + $html = $renderer->toHtml($content); + + // Apply custom Tailwind CSS classes for dark mode compatibility + $html = $this->applyCustomStyling($html); + + return $html; + } + + private function applyCustomStyling(string $html): string + { // Headers - $html = preg_replace('/^### (.*?)$/m', '
]*>/', '
', $html); - // Italic text - $html = preg_replace('/\*(.*?)\*/', '$1', $html); - $html = preg_replace('/_(.*?)_/', '$1', $html); + // Lists + $html = preg_replace('/
$1
', $html);
+ // Code blocks and inline code
+ $html = preg_replace('/]*>/', '', $html); + $html = preg_replace('/]*>/', '
', $html); - // Inline code - $html = preg_replace('/`([^`]+)`/', '
$1
', $html); + // Links - Apply styling to existing markdown links + $html = preg_replace('/]*)>/', '', $html); - // Links - $html = preg_replace('/\[([^\]]+)\]\(([^)]+)\)/', '$1', $html); + // Convert plain URLs to clickable links (that aren't already in tags) + $html = preg_replace('/(?)(?"]+)(?![^<]*<\/a>)/', '$1', $html); - // Line breaks (convert double newlines to paragraphs) - $paragraphs = preg_split('/\n\s*\n/', trim($html)); - $html = ''.implode('
', $paragraphs).'
'; + // Strong/bold text + $html = preg_replace('/]*>/', '', $html); - // Single line breaks - $html = preg_replace('/\n/', '
', $html); - - // Unordered lists - $html = preg_replace('/^\- (.*)$/m', '- • $1
', $html); - $html = preg_replace('/(- .*<\/li>)/s', '
$1
', $html); + // Emphasis/italic text + $html = preg_replace('/]*>/', '', $html); return $html; } diff --git a/changelogs/2025-05.json b/changelogs/2025-05.json new file mode 100644 index 000000000..98ddcffe4 --- /dev/null +++ b/changelogs/2025-05.json @@ -0,0 +1,17 @@ +{ + "entries": [ + { + "tag_name": "v4.0.0-beta.418", + "title": "v4.0.0-beta.418", + "content": "- fix(core): Clean up Horizon Redis data every hour.\r\n- fix(ui): Infinite loop on requesting a png file on new resource page.\r\n\r\n## What's Changed\r\n* v4.0.0-beta.418 by @andrasbacsai in https://github.com/coollabsio/coolify/pull/5793\r\n\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.417...v4.0.0-beta.418", + "published_at": "2025-05-09T06:30:49.000000Z" + }, + { + "tag_name": "v4.0.0-beta.417", + "title": "v4.0.0-beta.417", + "content": "- fix(core): Cleanup redis data every 10 minutes.\r\n- fix(core): Revert jobs to be `dontRelease` as they were before the redis/job problems started.\r\n\r\n## What's Changed\r\n* v4.0.0-beta.417 by @andrasbacsai in https://github.com/coollabsio/coolify/pull/5784\r\n\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.416...v4.0.0-beta.417", + "published_at": "2025-05-07T21:14:23.000000Z" + } + ], + "last_updated": "2025-08-10T10:20:51.376736Z" +} \ No newline at end of file diff --git a/changelogs/2025-06.json b/changelogs/2025-06.json new file mode 100644 index 000000000..052184a7f --- /dev/null +++ b/changelogs/2025-06.json @@ -0,0 +1,23 @@ +{ + "entries": [ + { + "tag_name": "v4.0.0-beta.420.1", + "title": "v4.0.0-beta.420.1", + "content": "- feat(migrations): add optimized indexes to activity_log for improved query performance\r\n- fix(shared): refactor gzip handling for Pocketbase in newParser function for improved clarity\r\n\r\n## What's Changed\r\n* v4.0.0-beta.420.1 by @andrasbacsai in https://github.com/coollabsio/coolify/pull/6069\r\n\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.420...v4.0.0-beta.420.1", + "published_at": "2025-06-26T20:27:21.000000Z" + }, + { + "tag_name": "v4.0.0-beta.420", + "title": "v4.0.0-beta.420", + "content": "## Changes\r\n- feat(core): set custom API rate limit\r\n- feat(auth): Add Discord OAuth Provider\r\n- feat(auth): Add Clerk OAuth Provider\r\n- feat(auth): add Zitadel OAuth Provider\r\n- feat(service): enhance service status handling and UI updates\r\n- feat(service): update Changedetection template\r\n- feat(cleanup): add functionality to delete teams with no members or servers in CleanupStuckedResources command\r\n- feat(settings): add sponsorship popup toggle and corresponding database migration\r\n- fix(parser): enable gzip compression conditionally for Pocketbase images and streamline service creation logic\r\n- fix(ui): adjust layout of deployments section for improved alignment\r\n- fix(ui): refine API token creation form and update helper text for clarity\r\n- fix(routes): update middleware for deploy route to use 'api.ability:deploy'\r\n- fix(ui): update confirmation button text for stopping database and service\r\n- fix(ui): enhance status refresh buttons with loading indicators\r\n- fix(parser): improve FQDN generation and update environment variable handling\r\n- fix(github): changing github app breaks the webhook. it does not anymore\r\n- fix(ssh): scp requires square brackets for ipv6\r\n- fix(service): audiobookshelf healthcheck command\r\n- fix(service): downgrade Evolution API phone version \r\n- fix(service): disable healthcheck logging for Gotenberg\r\n- fix(service): Joplin volume name\r\n- fix(ui): Multiple dropdown on the service terminal view (dropception)\r\n- refactor(service): update Hoarder to their new name karakeep\r\n- refactor(user): streamline user deletion process and enhance team management logic\r\n- refactor(email): streamline SMTP and resend settings logic for improved clarity\r\n- chore(service): Update Evolution API image to the official one\r\n\r\n## New Services\r\n- feat(service): add Miniflux service\r\n- feat(service): add Pingvin Share service\r\n\r\n## Issues\r\n- fix https://github.com/coollabsio/coolify/issues/5992\r\n- fix https://github.com/coollabsio/coolify/issues/5998\r\n\r\n## What's Changed\r\n* Set a custom api throttle limit so internal applications can automate coolify by @alnutile in https://github.com/coollabsio/coolify/pull/5984\r\n* v4.0.0-beta.420 by @peaklabs-dev in https://github.com/coollabsio/coolify/pull/6008\r\n\r\n## New Contributors\r\n* @alnutile made their first contribution in https://github.com/coollabsio/coolify/pull/5984\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.419...v4.0.0-beta.420", + "published_at": "2025-06-26T10:23:45.000000Z" + }, + { + "tag_name": "v4.0.0-beta.419", + "title": "v4.0.0-beta.419", + "content": "## Changes\r\n\r\n- feat(core): Enable Sentinel by default.\r\n- feat(security): New Security view for servers, that includes server patching through the UI\r\n- feat(ui): Upgrade UI to TailwindCSS v4\r\n- feat(terminal): implement resize handling with ResizeObserver for improved terminal responsiveness!\r\n- feat(api): Add `connect_to_docker_network` setting to App creation API \r\n- feat(api): Add latest query param to Service restart API\r\n- feat(core): Improve Pull Request comment message\r\n- feat(core): Add support for `postmarkos` & `fedora-asahi-remix` distros\r\n- feat(service): update Maybe service and adjust it for the new release\r\n- feat(oauth): set redirect uri as optional and add default value\r\n- feat(terminal): enable/disable web terminal access by server\r\n- feat(services): parallel stop services so the stop/restart process woudl be faster\r\n- feat(services): if a service contains more than 5 services, the timeout is decreased to 10 seconds when stopping them\r\n- feat(terminal-connection): enhance terminal connection handling with auto-connect feature and improved status messaging\r\n- feat(activity-monitor): implement auto-scrolling functionality and dynamic content observation for improved user experience\r\n- feat(utf8-handling): implement UTF-8 sanitization for command outputs and enhance error handling in logs processing\r\n- fix(database-backup): add MongoDB credential extraction and backup handling to DatabaseBackupJob\r\n- fix(terminal): Terminal through Cloudflare tunnel works?!\r\n- fix(core): Start proxy by default.\r\n- fix(jobs): Jobs that is running on the same server now have unique id, so they are not block eachother.\r\n- fix(select-component): enhance user interaction by adding cursor styles and disabling selection during processing\r\n- fix(modal-confirmation): decode HTML entities in confirmation text to ensure proper display\r\n- fix(core): Sentinel based status updates handles pull request based updates better\r\n- fix(ui): prevent preview deployments view access with deploy_key based apps\r\n- fix(email-notifications): change notify method to notifyNow for immediate test email delivery\r\n- fix(ApplicationDeploymentJob): ensure correct COOLIFY_FQDN/COOLIFY_URL values\r\n- fix(service): Neon WS Proxy service not working on ARM64\r\n- fix(service): documenso startup and mail\r\n- fix(service): Bugsink\r\n- fix(service): Authentik\r\n- fix(service): add missing ENVs to NTFY service\r\n- fix(service): Convex\r\n- fix(service): Snapdrop `no matching manifest` error\r\n- fix(service): use the same volume between chatwoot and sidekiq\r\n- fix(api): Nullable `destination_uuid` on service update API request\r\n- improvement(database-detection): enhance isDatabaseImage function to utilize service configuration for improved detection accuracy\r\n- chore(service): update Immich service\r\n- chore(service): Rename hoarder service to karakeep\r\n- chore(deps): upgrade logdrain Fluent Bit to 4.0\r\n- chore(deps): upgrade Node in the production Dockerfile to v24, to fix a vulnerability\r\n- chore(deps): update Authentik service to 2025.4.1 \r\n- refactor(install-scripts): update Docker installation process to include manual installation fallback and improve error handling\r\n- docs(service): add new docs link for zipline\r\n\r\n## New Services\r\n\r\n- feat(service): Passbolt service\r\n- feat(service): Typesense service\r\n- feat(service): Seafile service\r\n- feat(service): Netbird-Client service \r\n- feat(service): Yamtrack service\r\n- feat(service): add PG Back Web service\r\n- feat(service): Vert service\r\n- feat(service): Soketi App Manager - UI for your Soketi.\r\n- feat(service): Apache Superset service\r\n- feat(service): One Time Secret service\r\n- feat(service): Diun service \r\n- feat(service): Marimo service\r\n- feat(service): Navidrome service\r\n- feat(service): Leantime service\r\n- feat(service): Ryot service \r\n- feat(service): Observium service\r\n- feat(service): Memos service\r\n- feat(service): Limesurvey service\r\n- feat(service): Paymenter service\r\n- feat(service): CodiMD service\r\n- feat(service): OrangeHRM service\r\n- feat(service): Grist service\r\n\r\n## Issues\r\n- fix https://github.com/coollabsio/coolify/issues/5226\r\n- fix https://github.com/coollabsio/coolify/issues/4684\r\n- fix https://github.com/coollabsio/coolify/issues/5569\r\n- adds https://github.com/coollabsio/coolify/discussions/5578\r\n- fix https://github.com/coollabsio/coolify/issues/5790\r\n- fix https://github.com/coollabsio/coolify/issues/4719\r\n- fix https://github.com/coollabsio/coolify/issues/3437\r\n- fix https://github.com/coollabsio/coolify/issues/5897\r\n- adds https://github.com/coollabsio/coolify/discussions/4857\r\n- fix #5911\r\n- fix #5917\r\n- fix #5916\r\n- fix #5915\r\n- fix #5907\r\n- fix #5756\r\n- fix #5906\r\n- fix https://github.com/coollabsio/coolify/issues/5932\r\n- fix https://github.com/coollabsio/coolify/issues/5978\r\n\r\n## What's Changed\r\n* fix(service): rolling updates by @derdaele in https://github.com/coollabsio/coolify/pull/5731\r\n* Fix system theme causing light mode defaults in checkTheme() by @The-Best-Codes in https://github.com/coollabsio/coolify/pull/5740\r\n* chore(deps-dev): bump vite from 6.2.6 to 6.3.4 by @dependabot in https://github.com/coollabsio/coolify/pull/5743\r\n* fix(DatabaseBackupJob): escape PostgreSQL password in backup command by @busybox11 in https://github.com/coollabsio/coolify/pull/5759\r\n* Add soketi-app-manager service template \ud83d\ude80 by @rahulhaque in https://github.com/coollabsio/coolify/pull/4797\r\n* BugSink Integration - fix - working with cloudflared by @neooriginal in https://github.com/coollabsio/coolify/pull/5178\r\n* Improve ApplicationPullRequestUpdateJob message content by @itsisak in https://github.com/coollabsio/coolify/pull/5549\r\n* Authentik update - 2025.2.4 by @Datenschmutz in https://github.com/coollabsio/coolify/pull/5576\r\n* install: Add support for postmarketOS by @manoedinata in https://github.com/coollabsio/coolify/pull/5608\r\n* fix(constants): adding 'fedora-asahi-remix' as a supported OS by @JCluzet in https://github.com/coollabsio/coolify/pull/5646\r\n* fix(api): allow nullable destination_uuid by @megheaiulian in https://github.com/coollabsio/coolify/pull/5683\r\n* chore(deps): upgrade Fluent Bit to 4.0 by @noahstreller in https://github.com/coollabsio/coolify/pull/5719\r\n* Rename hoarder service to karakeep by @MohamedBassem in https://github.com/coollabsio/coolify/pull/5607\r\n* Update Supabase services and Postgres image version by @pujan-modha in https://github.com/coollabsio/coolify/pull/5708\r\n* feat: Add memos service tamplate by @leonovk in https://github.com/coollabsio/coolify/pull/5032\r\n* Update documenso.yaml by @MeXaaR in https://github.com/coollabsio/coolify/pull/5737\r\n* Upgrade Tailwind to v4 by @johngerome in https://github.com/coollabsio/coolify/pull/5710\r\n* feat(templates): add navidrome service template by @antond15 in https://github.com/coollabsio/coolify/pull/5022\r\n* Adding Passbolt as a template by @kunumigab in https://github.com/coollabsio/coolify/pull/5769\r\n* fix(compose): ntfy - add proxy and web_push_file settings by @leikoilja in https://github.com/coollabsio/coolify/pull/5629\r\n* Add Vert service by @FranckKe in https://github.com/coollabsio/coolify/pull/5663\r\n* Add Ryot service by @IgnisDa in https://github.com/coollabsio/coolify/pull/5232\r\n* feat(service): add Marimo by @peter-gy in https://github.com/coollabsio/coolify/pull/5559\r\n* Add service template Diun by @Datenschmutz in https://github.com/coollabsio/coolify/pull/5113\r\n* Add Observium Service by @Rustypredator in https://github.com/coollabsio/coolify/pull/5613\r\n* Add Leantime Service Template by @marcelfolaron in https://github.com/coollabsio/coolify/pull/5792\r\n* Adding Limesurvey as a service by @howardshand in https://github.com/coollabsio/coolify/pull/5751\r\n* feat: add Paymenter template by @CorwinDev in https://github.com/coollabsio/coolify/pull/5809\r\n* feat: New Service CodiMD by @Manaf941 in https://github.com/coollabsio/coolify/pull/4867\r\n* Update convex.yaml by @NarendraPatwardhan in https://github.com/coollabsio/coolify/pull/5827\r\n* feat: Add Typesense service template by @dusanbre in https://github.com/coollabsio/coolify/pull/5643\r\n* fix(service): Snapdrop `no matching manifest` error by @ShadowArcanist in https://github.com/coollabsio/coolify/pull/5849\r\n* Authentik template update - Release 2025.4.1 by @Datenschmutz in https://github.com/coollabsio/coolify/pull/5830\r\n* fix(service): use the same volume between chatwoot and sidekiq by @YAlmuzaini in https://github.com/coollabsio/coolify/pull/5851\r\n* feat: new service Yamtrack by @CrazyTim71 in https://github.com/coollabsio/coolify/pull/5845\r\n* feat(service): add PG Back Web service by @ejscheepers in https://github.com/coollabsio/coolify/pull/5079\r\n* feat(service): update Maybe service by @albertorizzi in https://github.com/coollabsio/coolify/pull/5795\r\n* fix(docker-compose build) added --no-cache flag by @christopherpickering in https://github.com/coollabsio/coolify/pull/5794\r\n* feat(oauth): set redirect uri as optional and add default value by @arnaud-dezandee in https://github.com/coollabsio/coolify/pull/5760\r\n* feat(service): add apache superset service by @nktnet1 in https://github.com/coollabsio/coolify/pull/4891\r\n* feat(service): add One Time Secret service by @nktnet1 in https://github.com/coollabsio/coolify/pull/5650\r\n* feat(service): add Seafile service by @nktnet1 in https://github.com/coollabsio/coolify/pull/5817\r\n* fix(ApplicationDeploymentJob): ensure correct COOLIFY_FQDN/COOLIFY_UR\u2026 by @bayramkazik in https://github.com/coollabsio/coolify/pull/5833\r\n* feat(service): add Netbird-Client service by @kunumigab in https://github.com/coollabsio/coolify/pull/5873\r\n* feat(service): add OrangeHRM and Grist services by @howardshand in https://github.com/coollabsio/coolify/pull/5212\r\n* fix(service): Neon WS Proxy service not working on ARM64 by @ShadowArcanist in https://github.com/coollabsio/coolify/pull/5887\r\n* chore(service): update Immich service by @CrazyTim71 in https://github.com/coollabsio/coolify/pull/5886\r\n* feat(api): Add latest query param to Service restart API by @dusanbre in https://github.com/coollabsio/coolify/pull/5881\r\n* Add connect_to_docker_network setting to the application API by @nurdism in https://github.com/coollabsio/coolify/pull/5691\r\n* docs(zipline): adding new docs link for zipline by @baptisthecht in https://github.com/coollabsio/coolify/pull/5912\r\n* Capitalize \"WordPress\" properly by @slaFFik in https://github.com/coollabsio/coolify/pull/5958\r\n* change db proxy to use volume mount for config by @djsisson in https://github.com/coollabsio/coolify/pull/5981\r\n* v4.0.0-beta.419 by @andrasbacsai in https://github.com/coollabsio/coolify/pull/5815\r\n* Fine tunes for v419 by @andrasbacsai in https://github.com/coollabsio/coolify/pull/5995\r\n* Small fixes before release by @andrasbacsai in https://github.com/coollabsio/coolify/pull/5999\r\n\r\n## New Contributors\r\n* @derdaele made their first contribution in https://github.com/coollabsio/coolify/pull/5731\r\n* @The-Best-Codes made their first contribution in https://github.com/coollabsio/coolify/pull/5740\r\n* @rahulhaque made their first contribution in https://github.com/coollabsio/coolify/pull/4797\r\n* @neooriginal made their first contribution in https://github.com/coollabsio/coolify/pull/5178\r\n* @itsisak made their first contribution in https://github.com/coollabsio/coolify/pull/5549\r\n* @manoedinata made their first contribution in https://github.com/coollabsio/coolify/pull/5608\r\n* @JCluzet made their first contribution in https://github.com/coollabsio/coolify/pull/5646\r\n* @noahstreller made their first contribution in https://github.com/coollabsio/coolify/pull/5719\r\n* @MohamedBassem made their first contribution in https://github.com/coollabsio/coolify/pull/5607\r\n* @pujan-modha made their first contribution in https://github.com/coollabsio/coolify/pull/5708\r\n* @leonovk made their first contribution in https://github.com/coollabsio/coolify/pull/5032\r\n* @MeXaaR made their first contribution in https://github.com/coollabsio/coolify/pull/5737\r\n* @johngerome made their first contribution in https://github.com/coollabsio/coolify/pull/5710\r\n* @antond15 made their first contribution in https://github.com/coollabsio/coolify/pull/5022\r\n* @leikoilja made their first contribution in https://github.com/coollabsio/coolify/pull/5629\r\n* @IgnisDa made their first contribution in https://github.com/coollabsio/coolify/pull/5232\r\n* @peter-gy made their first contribution in https://github.com/coollabsio/coolify/pull/5559\r\n* @Rustypredator made their first contribution in https://github.com/coollabsio/coolify/pull/5613\r\n* @marcelfolaron made their first contribution in https://github.com/coollabsio/coolify/pull/5792\r\n* @CorwinDev made their first contribution in https://github.com/coollabsio/coolify/pull/5809\r\n* @Manaf941 made their first contribution in https://github.com/coollabsio/coolify/pull/4867\r\n* @NarendraPatwardhan made their first contribution in https://github.com/coollabsio/coolify/pull/5827\r\n* @dusanbre made their first contribution in https://github.com/coollabsio/coolify/pull/5643\r\n* @YAlmuzaini made their first contribution in https://github.com/coollabsio/coolify/pull/5851\r\n* @CrazyTim71 made their first contribution in https://github.com/coollabsio/coolify/pull/5845\r\n* @christopherpickering made their first contribution in https://github.com/coollabsio/coolify/pull/5794\r\n* @arnaud-dezandee made their first contribution in https://github.com/coollabsio/coolify/pull/5760\r\n* @bayramkazik made their first contribution in https://github.com/coollabsio/coolify/pull/5833\r\n* @slaFFik made their first contribution in https://github.com/coollabsio/coolify/pull/5958\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.418...v4.0.0-beta.419", + "published_at": "2025-06-17T12:39:00.000000Z" + } + ], + "last_updated": "2025-08-10T10:20:51.375511Z" +} \ No newline at end of file diff --git a/changelogs/2025-07.json b/changelogs/2025-07.json new file mode 100644 index 000000000..0b86de503 --- /dev/null +++ b/changelogs/2025-07.json @@ -0,0 +1,35 @@ +{ + "entries": [ + { + "tag_name": "v4.0.0-beta.420.6", + "title": "v4.0.0-beta.420.6", + "content": "## Changes\r\n- chore(deps): update composer dependencies to fix https://github.com/advisories/GHSA-29cq-5w36-x7w3\r\n\r\n## What's Changed\r\n* 4.0.0-beta.420.6 by @peaklabs-dev in https://github.com/coollabsio/coolify/pull/6221\r\n\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.420.5...v4.0.0-beta.420.6", + "published_at": "2025-07-18T18:45:44.000000Z" + }, + { + "tag_name": "v4.0.0-beta.420.5", + "title": "v4.0.0-beta.420.5", + "content": "- refactor(postgresql): improve layout and spacing in SSL and Proxy configuration sections for better UI consistency\r\n- fix(database): ensure internal port defaults correctly for unsupported database types in StartDatabaseProxy\r\n\r\n## What's Changed\r\n* v4.0.0-beta.420.5 by @andrasbacsai in https://github.com/coollabsio/coolify/pull/6156\r\n\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.420.4...v4.0.0-beta.420.5", + "published_at": "2025-07-08T19:14:04.000000Z" + }, + { + "tag_name": "v4.0.0-beta.420.4", + "title": "v4.0.0-beta.420.4", + "content": "# POSSIBLE BREAKING CHANGE\r\n- fix(envs): enhance COOLIFY_URL and COOLIFY_FQDN variable generation for better compatibility for applications and services.\r\n - **Switched URL with FQDN in case of applications, so they are correct now.**\r\n\r\n--- \r\n- feat(envs): New environment variables for `docker compose` based application. You can use `SERVICE_FQDN_` and `SERVICE_URL_ ` the same way as in services. For details check this: https://github.com/coollabsio/coolify/issues/6124#issuecomment-3045186382\r\n- fix(redis): Cleanup old jobs on Coolify start.\r\n- fix(database): Unsupported database with SSL.\r\n- fix(jobs): Sentinel update job fails if compose is invalid for a service/app.\r\n- fix(installscript): Add Cachyos support + reuse env variable for public ip.\r\n- fix(envs): Generate literal env variables better.\r\n- fix(scheduling): change redis cleanup command frequency from hourly to weekly for better resource management\r\n\r\n# Issues\r\n- fix https://github.com/coollabsio/coolify/issues/6142\r\n- fix https://github.com/coollabsio/coolify/issues/6134\r\n- fix https://github.com/coollabsio/coolify/issues/6141\r\n- fix https://github.com/coollabsio/coolify/issues/2470\r\n\r\n## What's Changed\r\n* fix(service): Postiz shows no available server on latest version by @ShadowArcanist in https://github.com/coollabsio/coolify/pull/6144\r\n* Typo Correction on modal by @Nathanjms in https://github.com/coollabsio/coolify/pull/6130\r\n* fix(install.sh): use IPV4_PUBLIC_IP variable in output instead of repeated curl by @dewstouh in https://github.com/coollabsio/coolify/pull/6129\r\n* interpret cachyos as arch in the install script by @flickowoa in https://github.com/coollabsio/coolify/pull/6127\r\n* v4.0.0-beta.420.4 by @andrasbacsai in https://github.com/coollabsio/coolify/pull/6146\r\n\r\n## New Contributors\r\n* @dewstouh made their first contribution in https://github.com/coollabsio/coolify/pull/6129\r\n* @flickowoa made their first contribution in https://github.com/coollabsio/coolify/pull/6127\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.420.3...v4.0.0-beta.420.4", + "published_at": "2025-07-08T08:58:14.000000Z" + }, + { + "tag_name": "v4.0.0-beta.420.3", + "title": "v4.0.0-beta.420.3", + "content": "- fix(shared): enhance FQDN generation logic for services in newParser function\r\n- fix(ui): light mode, configuration changed popup fixed\r\n\r\n## What's Changed\r\n* v4.0.0-beta.420.3 by @andrasbacsai in https://github.com/coollabsio/coolify/pull/6120\r\n\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.420.2...v4.0.0-beta.420.3", + "published_at": "2025-07-03T19:31:13.000000Z" + }, + { + "tag_name": "v4.0.0-beta.420.2", + "title": "v4.0.0-beta.420.2", + "content": "- fix(supabase): Fix supabase template\r\n- fix(database): proxy ssl port if ssl is enabled\r\n- fix(ui): enhance terminal access messaging to clarify server functionality and terminal status\r\n- fix(server): prepend 'mux_' to UUID in muxFilename method for consistent naming\r\n- fix(jobs): update middleware to use expireAfter for WithoutOverlapping in multiple job classes\r\n- fix(ui): improve destination selection description for clarity in resource segregation\r\n- fix(terminal): ensure shell execution only uses valid shell if available in terminal command\r\n- refactor(ui): remove unnecessary step3ButtonText attributes from modal confirmation components for cleaner code\r\n- refactor(ui): separate views for instance settings to separate paths to make it cleaner\r\n- refactor(ui): enhance project cloning interface with improved table layout for server and resource selection\r\n\r\n# Issues\r\n- fix #6074\r\n- fix #6022\r\n\r\n## What's Changed\r\n* fix: 500 status code when trying to clone an environment by @HicaroD in https://github.com/coollabsio/coolify/pull/6071\r\n* Update Authentik to version 2025.6.3 by @Datenschmutz in https://github.com/coollabsio/coolify/pull/6100\r\n* Update Appwrite services and image version (1.7.4) by @pujan-modha in https://github.com/coollabsio/coolify/pull/6099\r\n* feat(template): added excalidraw by @nktnet1 in https://github.com/coollabsio/coolify/pull/6095\r\n* v4.0.0-beta.420.2 by @andrasbacsai in https://github.com/coollabsio/coolify/pull/6096\r\n\r\n## New Contributors\r\n* @smad-bro made their first contribution in https://github.com/coollabsio/coolify/pull/6031\r\n* @HicaroD made their first contribution in https://github.com/coollabsio/coolify/pull/6071\r\n\r\n**Full Changelog**: https://github.com/coollabsio/coolify/compare/v4.0.0-beta.420.1...v4.0.0-beta.420.2", + "published_at": "2025-07-03T13:55:03.000000Z" + } + ], + "last_updated": "2025-08-10T10:20:51.373867Z" +} \ No newline at end of file diff --git a/composer.json b/composer.json index 68b0fb066..38756edf9 100644 --- a/composer.json +++ b/composer.json @@ -47,6 +47,7 @@ "socialiteproviders/zitadel": "^4.2", "spatie/laravel-activitylog": "^4.10.2", "spatie/laravel-data": "^4.17.0", + "spatie/laravel-markdown": "^2.7", "spatie/laravel-ray": "^1.40.2", "spatie/laravel-schemaless-attributes": "^2.5.1", "spatie/url": "^2.4", @@ -127,4 +128,4 @@ "@php artisan key:generate --ansi" ] } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index acf153038..c7de9ad34 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "52a680a0eb446dcaa74bc35e158aca57", + "content-hash": "a78cf8fdfec25eac43de77c05640dc91", "packages": [ { "name": "amphp/amp", @@ -7902,6 +7902,66 @@ ], "time": "2025-05-08T15:41:09+00:00" }, + { + "name": "spatie/commonmark-shiki-highlighter", + "version": "2.5.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/commonmark-shiki-highlighter.git", + "reference": "595c7e0b45d4a63b17dfc1ccbd13532d431ec351" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/commonmark-shiki-highlighter/zipball/595c7e0b45d4a63b17dfc1ccbd13532d431ec351", + "reference": "595c7e0b45d4a63b17dfc1ccbd13532d431ec351", + "shasum": "" + }, + "require": { + "league/commonmark": "^2.4.2", + "php": "^8.0", + "spatie/shiki-php": "^2.2.2", + "symfony/process": "^5.4|^6.4|^7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.19|^v3.49.0", + "phpunit/phpunit": "^9.5", + "spatie/phpunit-snapshot-assertions": "^4.2.7", + "spatie/ray": "^1.28" + }, + "type": "commonmark-extension", + "autoload": { + "psr-4": { + "Spatie\\CommonMarkShikiHighlighter\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Highlight code blocks with league/commonmark and Shiki", + "homepage": "https://github.com/spatie/commonmark-shiki-highlighter", + "keywords": [ + "commonmark-shiki-highlighter", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/commonmark-shiki-highlighter/tree/2.5.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-01-13T11:25:47+00:00" + }, { "name": "spatie/laravel-activitylog", "version": "4.10.2", @@ -8076,6 +8136,82 @@ ], "time": "2025-06-25T11:36:37+00:00" }, + { + "name": "spatie/laravel-markdown", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-markdown.git", + "reference": "353e7f9fae62826e26cbadef58a12ecf39685280" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-markdown/zipball/353e7f9fae62826e26cbadef58a12ecf39685280", + "reference": "353e7f9fae62826e26cbadef58a12ecf39685280", + "shasum": "" + }, + "require": { + "illuminate/cache": "^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^9.0|^10.0|^11.0|^12.0", + "illuminate/view": "^9.0|^10.0|^11.0|^12.0", + "league/commonmark": "^2.6.0", + "php": "^8.1", + "spatie/commonmark-shiki-highlighter": "^2.5", + "spatie/laravel-package-tools": "^1.4.3" + }, + "require-dev": { + "brianium/paratest": "^6.2|^7.8", + "nunomaduro/collision": "^5.3|^6.0|^7.0|^8.0", + "orchestra/testbench": "^6.15|^7.0|^8.0|^10.0", + "pestphp/pest": "^1.22|^2.0|^3.7", + "phpunit/phpunit": "^9.3|^11.5.3", + "spatie/laravel-ray": "^1.23", + "spatie/pest-plugin-snapshots": "^1.1|^2.2|^3.0", + "vimeo/psalm": "^4.8|^6.7" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\LaravelMarkdown\\MarkdownServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\LaravelMarkdown\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "A highly configurable markdown renderer and Blade component for Laravel", + "homepage": "https://github.com/spatie/laravel-markdown", + "keywords": [ + "Laravel-Markdown", + "laravel", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/laravel-markdown/tree/2.7.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-02-21T13:43:18+00:00" + }, { "name": "spatie/laravel-package-tools", "version": "1.92.7", @@ -8515,6 +8651,71 @@ ], "time": "2025-04-18T08:17:40+00:00" }, + { + "name": "spatie/shiki-php", + "version": "2.3.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/shiki-php.git", + "reference": "a2e78a9ff8a1290b25d550be8fbf8285c13175c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/shiki-php/zipball/a2e78a9ff8a1290b25d550be8fbf8285c13175c5", + "reference": "a2e78a9ff8a1290b25d550be8fbf8285c13175c5", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^8.0", + "symfony/process": "^5.4|^6.4|^7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v3.0", + "pestphp/pest": "^1.8", + "phpunit/phpunit": "^9.5", + "spatie/pest-plugin-snapshots": "^1.1", + "spatie/ray": "^1.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\ShikiPhp\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rias Van der Veken", + "email": "rias@spatie.be", + "role": "Developer" + }, + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Highlight code using Shiki in PHP", + "homepage": "https://github.com/spatie/shiki-php", + "keywords": [ + "shiki", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/shiki-php/tree/2.3.2" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-02-21T14:16:57+00:00" + }, { "name": "spatie/url", "version": "2.4.0", diff --git a/database/migrations/2025_08_07_142403_create_user_changelog_reads_table.php b/database/migrations/2025_08_07_142403_create_user_changelog_reads_table.php index 4c340d106..db8a42fb7 100644 --- a/database/migrations/2025_08_07_142403_create_user_changelog_reads_table.php +++ b/database/migrations/2025_08_07_142403_create_user_changelog_reads_table.php @@ -14,13 +14,13 @@ return new class extends Migration Schema::create('user_changelog_reads', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained()->onDelete('cascade'); - $table->string('changelog_identifier'); + $table->string('release_tag'); // GitHub tag_name (e.g., "v4.0.0-beta.420.6") $table->timestamp('read_at'); $table->timestamps(); - $table->unique(['user_id', 'changelog_identifier']); + $table->unique(['user_id', 'release_tag']); $table->index('user_id'); - $table->index('changelog_identifier'); + $table->index('release_tag'); }); } diff --git a/resources/views/livewire/settings-dropdown.blade.php b/resources/views/livewire/settings-dropdown.blade.php index 11e79719b..5a703459c 100644 --- a/resources/views/livewire/settings-dropdown.blade.php +++ b/resources/views/livewire/settings-dropdown.blade.php @@ -7,14 +7,14 @@ // Load all entries when component initializes this.allEntries = @js($entries->toArray()); }, - markEntryAsRead(version) { + markEntryAsRead(tagName) { // Update the entry in our local Alpine data - const entry = this.allEntries.find(e => e.version === version); + const entry = this.allEntries.find(e => e.tag_name === tagName); if (entry) { entry.is_read = true; } // Call Livewire to update server-side - $wire.markAsRead(version); + $wire.markAsRead(tagName); }, markAllEntriesAsRead() { // Update all entries in our local Alpine data @@ -73,7 +73,7 @@ entries = entries.filter(entry => { return (entry.title?.toLowerCase().includes(searchLower) || entry.content?.toLowerCase().includes(searchLower) || - entry.version?.toLowerCase().includes(searchLower)); + entry.tag_name?.toLowerCase().includes(searchLower)); }); } @@ -124,7 +124,8 @@ class="px-1 dropdown-item-no-padding flex items-center justify-between"> What's New@@ -137,7 +138,8 @@ @@ -152,21 +154,24 @@ @@ -175,17 +180,19 @@Width-