diff --git a/web/src/lib/stores/websocket.ts b/web/src/lib/stores/websocket.ts index 6e896e8000..c543fdb4ff 100644 --- a/web/src/lib/stores/websocket.ts +++ b/web/src/lib/stores/websocket.ts @@ -25,7 +25,7 @@ export interface Events { on_person_thumbnail: (personId: string) => void; on_server_version: (serverVersion: ServerVersionResponseDto) => void; on_config_update: () => void; - on_new_release: (newRelase: ReleaseEvent) => void; + on_new_release: (newRelease: ReleaseEvent) => void; on_session_delete: (sessionId: string) => void; on_notification: (notification: NotificationDto) => void; } diff --git a/web/src/lib/utils.spec.ts b/web/src/lib/utils.spec.ts new file mode 100644 index 0000000000..169f42409c --- /dev/null +++ b/web/src/lib/utils.spec.ts @@ -0,0 +1,25 @@ +import { getReleaseType } from '$lib/utils'; + +describe('utils', () => { + describe(getReleaseType.name, () => { + it('should return "major" for major version changes', () => { + expect(getReleaseType({ major: 1, minor: 0, patch: 0 }, { major: 2, minor: 0, patch: 0 })).toBe('major'); + expect(getReleaseType({ major: 1, minor: 0, patch: 0 }, { major: 3, minor: 2, patch: 1 })).toBe('major'); + }); + + it('should return "minor" for minor version changes', () => { + expect(getReleaseType({ major: 1, minor: 0, patch: 0 }, { major: 1, minor: 1, patch: 0 })).toBe('minor'); + expect(getReleaseType({ major: 1, minor: 0, patch: 0 }, { major: 1, minor: 2, patch: 1 })).toBe('minor'); + }); + + it('should return "patch" for patch version changes', () => { + expect(getReleaseType({ major: 1, minor: 0, patch: 0 }, { major: 1, minor: 0, patch: 1 })).toBe('patch'); + expect(getReleaseType({ major: 1, minor: 0, patch: 0 }, { major: 1, minor: 0, patch: 5 })).toBe('patch'); + }); + + it('should return "none" for matching versions', () => { + expect(getReleaseType({ major: 1, minor: 0, patch: 0 }, { major: 1, minor: 0, patch: 0 })).toBe('none'); + expect(getReleaseType({ major: 1, minor: 2, patch: 3 }, { major: 1, minor: 2, patch: 3 })).toBe('none'); + }); + }); +}); diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index 09205a2fc9..c35fb6a893 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -21,6 +21,7 @@ import { unlinkOAuthAccount, type MemoryResponseDto, type PersonResponseDto, + type ServerVersionResponseDto, type SharedLinkResponseDto, type UserResponseDto, } from '@immich/sdk'; @@ -385,3 +386,22 @@ export function createDateFormatter(localeCode: string | undefined): DateFormatt }, }; } + +export const getReleaseType = ( + current: ServerVersionResponseDto, + newVersion: ServerVersionResponseDto, +): 'major' | 'minor' | 'patch' | 'none' => { + if (current.major !== newVersion.major) { + return 'major'; + } + + if (current.minor !== newVersion.minor) { + return 'minor'; + } + + if (current.patch !== newVersion.patch) { + return 'patch'; + } + + return 'none'; +}; diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index d2311a4204..c159c46136 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -18,7 +18,7 @@ websocketStore, type ReleaseEvent, } from '$lib/stores/websocket'; - import { copyToClipboard } from '$lib/utils'; + import { copyToClipboard, getReleaseType } from '$lib/utils'; import { isAssetViewerRoute } from '$lib/utils/navigation'; import type { ServerVersionResponseDto } from '@immich/sdk'; import { modalManager, setTranslations } from '@immich/ui'; @@ -85,8 +85,9 @@ const releaseVersion = semverToName(release.releaseVersion); const serverVersion = semverToName(release.serverVersion); + const type = getReleaseType(release.serverVersion, release.releaseVersion); - if (localStorage.getItem('appVersion') === releaseVersion) { + if (type === 'none' || type === 'patch' || localStorage.getItem('appVersion') === releaseVersion) { return; }