From b52188083a623f5f7d4dba584b7a82ac65a2ffa8 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner Date: Wed, 26 Nov 2025 10:20:06 +0100 Subject: [PATCH] Add update confirmation modal with changelog display - Add UpdateConfirmationModal component that shows changelog before update - Modify getVersionStatus to include release body (changelog) in response - Update VersionDisplay to show confirmation modal instead of starting update directly - Users must review changelog and click 'Proceed with Update' to start update - Ensures users see potential breaking changes before updating --- server.js | 2 +- .../_components/UpdateConfirmationModal.tsx | 175 ++++++++++++++++++ src/server/api/routers/version.ts | 3 +- 3 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 src/app/_components/UpdateConfirmationModal.tsx diff --git a/server.js b/server.js index 4f89231..fbc32fd 100644 --- a/server.js +++ b/server.js @@ -92,7 +92,7 @@ class ScriptExecutionHandler { /** * Handle WebSocket upgrade for our endpoint * @param {import('http').IncomingMessage} request - * @param {import('net').Socket} socket + * @param {import('stream').Duplex} socket * @param {Buffer} head */ handleUpgrade(request, socket, head) { diff --git a/src/app/_components/UpdateConfirmationModal.tsx b/src/app/_components/UpdateConfirmationModal.tsx new file mode 100644 index 0000000..3fb231e --- /dev/null +++ b/src/app/_components/UpdateConfirmationModal.tsx @@ -0,0 +1,175 @@ +'use client'; + +import { api } from '~/trpc/react'; +import { Button } from './ui/button'; +import { Badge } from './ui/badge'; +import { X, ExternalLink, Calendar, Tag, Loader2, AlertTriangle } from 'lucide-react'; +import { useRegisterModal } from './modal/ModalStackProvider'; +import ReactMarkdown from 'react-markdown'; +import remarkGfm from 'remark-gfm'; + +interface UpdateConfirmationModalProps { + isOpen: boolean; + onClose: () => void; + onConfirm: () => void; + releaseInfo: { + tagName: string; + name: string; + publishedAt: string; + htmlUrl: string; + body?: string; + } | null; + currentVersion: string; + latestVersion: string; +} + +export function UpdateConfirmationModal({ + isOpen, + onClose, + onConfirm, + releaseInfo, + currentVersion, + latestVersion +}: UpdateConfirmationModalProps) { + useRegisterModal(isOpen, { id: 'update-confirmation-modal', allowEscape: true, onClose }); + + if (!isOpen || !releaseInfo) return null; + + return ( +
+
+ {/* Header */} +
+
+ +
+

Confirm Update

+

+ Review the changelog before proceeding with the update +

+
+
+ +
+ + {/* Content */} +
+
+ {/* Version Info */} +
+
+
+

+ {releaseInfo.name || releaseInfo.tagName} +

+ + Latest + +
+ +
+
+
+ + {releaseInfo.tagName} +
+
+ + + {new Date(releaseInfo.publishedAt).toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric' + })} + +
+
+
+ Updating from + v{currentVersion} + to + v{latestVersion} +
+
+ + {/* Changelog */} + {releaseInfo.body ? ( +
+

Changelog

+
+

{children}

, + h2: ({children}) =>

{children}

, + h3: ({children}) =>

{children}

, + p: ({children}) =>

{children}

, + ul: ({children}) =>
    {children}
, + ol: ({children}) =>
    {children}
, + li: ({children}) =>
  • {children}
  • , + a: ({href, children}) => {children}, + strong: ({children}) => {children}, + em: ({children}) => {children}, + }} + > + {releaseInfo.body} +
    +
    +
    + ) : ( +
    +

    No changelog available for this release.

    +
    + )} + + {/* Warning */} +
    +
    + +
    +

    Important:

    +

    + Please review the changelog above for any breaking changes or important updates before proceeding. + The server will restart automatically after the update completes. +

    +
    +
    +
    +
    +
    + + {/* Footer */} +
    + + +
    +
    +
    + ); +} + diff --git a/src/server/api/routers/version.ts b/src/server/api/routers/version.ts index de60b05..06f61d3 100644 --- a/src/server/api/routers/version.ts +++ b/src/server/api/routers/version.ts @@ -111,7 +111,8 @@ export const versionRouter = createTRPCRouter({ tagName: release.tag_name, name: release.name, publishedAt: release.published_at, - htmlUrl: release.html_url + htmlUrl: release.html_url, + body: release.body } }; } catch (error) {