From f439a6cd9e9e6863db0f3eb04edf300b7a1a14ef Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Ronssin <65334819+jbronssin@users.noreply.github.com> Date: Wed, 23 Jul 2025 17:44:09 +0200 Subject: [PATCH] fix: normalize version number using semver.coerce in admin panel version info (#13348) ### Summary This PR fixes an inconsistency in the display of application versions in the Admin Panel. Previously, the "Current version" was displayed with a "v" prefix (e.g., `v1.1.1`), while the "Latest version" was displayed without it (e.g., `1.1.1`). ### Problem The inconsistency originated from two different data sources being handled differently in the backend: - `currentVersion` was read directly from the `APP_VERSION` configuration variable, which includes the "v" prefix. - `latestVersion` was fetched from the Docker Hub API, and the `semver.coerce()` function was used to parse it, which strips the "v" prefix. ![Jb ScreenShot 2025-07-22 at 16 47 05@2x](https://github.com/user-attachments/assets/b6243d03-2730-4958-8ad9-68f7e461bbe2) ### Solution The fix addresses the root cause in the [AdminPanelService] on the backend. The `semver.coerce()` function is now also applied to the `currentVersion`. This ensures that both version numbers are normalized at the data source, providing a consistent format before being sent to the frontend. This is a cleaner approach than manipulating the data on the client side. **Before:** - Current version: `v1.1.1` - Latest version: `1.1.1` **After:** - Current version: `1.1.1` - Latest version: `1.1.1` --------- Co-authored-by: prastoin --- .../admin-panel/admin-panel.service.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.service.ts b/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.service.ts index c199a52d6..bd9c56ce7 100644 --- a/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.service.ts +++ b/packages/twenty-server/src/engine/core-modules/admin-panel/admin-panel.service.ts @@ -4,6 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import axios from 'axios'; import semver from 'semver'; import { Repository } from 'typeorm'; +import * as z from 'zod'; import { ConfigVariable } from 'src/engine/core-modules/admin-panel/dtos/config-variable.dto'; import { ConfigVariablesGroupData } from 'src/engine/core-modules/admin-panel/dtos/config-variables-group.dto'; @@ -199,23 +200,25 @@ export class AdminPanelService { const currentVersion = this.twentyConfigService.get('APP_VERSION'); try { - const response = await axios.get( + const rawResponse = await axios.get( 'https://hub.docker.com/v2/repositories/twentycrm/twenty/tags?page_size=100', ); + const response = z + .object({ + data: z.object({ + results: z.array(z.object({ name: z.string() })), + }), + }) + .parse(rawResponse); const versions = response.data.results - // @ts-expect-error legacy noImplicitAny - .filter((tag) => tag && tag.name !== 'latest') - // @ts-expect-error legacy noImplicitAny - .map((tag) => semver.coerce(tag.name)?.version) - // @ts-expect-error legacy noImplicitAny - .filter((version) => version !== undefined); + .map((tag) => tag.name) + .filter((name) => name !== 'latest' && semver.valid(name)); if (versions.length === 0) { return { currentVersion, latestVersion: 'latest' }; } - // @ts-expect-error legacy noImplicitAny versions.sort((a, b) => semver.compare(b, a)); const latestVersion = versions[0];