From 3b3a18992b95fe2d031c4f5e202ddf467423afad Mon Sep 17 00:00:00 2001 From: KodekaTeam Date: Wed, 10 Jun 2026 14:10:25 +0700 Subject: [PATCH] style(ui): collapse long error messages into issue details --- src/app/api-keys/page.tsx | 21 ++--- src/app/apps/installed/page.tsx | 37 +++----- src/app/firewall/page.tsx | 22 ++--- src/app/globals.css | 2 + .../containers/[containerId]/page.tsx | 46 ++++------ .../environments/[environmentId]/page.tsx | 16 ++-- src/app/security/page.tsx | 23 ++--- .../servers/components/ServerConfigModal.tsx | 32 +++---- src/app/users/page.tsx | 22 ++--- src/components/IssueDetailsSummary.tsx | 92 +++++++++++++++++++ 10 files changed, 163 insertions(+), 150 deletions(-) create mode 100644 src/components/IssueDetailsSummary.tsx diff --git a/src/app/api-keys/page.tsx b/src/app/api-keys/page.tsx index 8010b36..2593f3f 100644 --- a/src/app/api-keys/page.tsx +++ b/src/app/api-keys/page.tsx @@ -2,6 +2,7 @@ import ConfirmActionDialog from "@/components/ConfirmActionDialog"; import GuardedPage from "@/components/GuardedPage"; +import IssueDetailsSummary from "@/components/IssueDetailsSummary"; import { apiKeys as apiKeysApi, type ApiKeyExpiryOption, @@ -529,21 +530,11 @@ export default function ApiKeysPage() { {error && ( -
- - {error} -
+ )} {loading ? ( diff --git a/src/app/apps/installed/page.tsx b/src/app/apps/installed/page.tsx index 709b1e6..b2c6380 100644 --- a/src/app/apps/installed/page.tsx +++ b/src/app/apps/installed/page.tsx @@ -24,6 +24,7 @@ import { } from "lucide-react"; import DashboardLayout from "@/components/DashboardLayout"; import ConfirmActionDialog from "@/components/ConfirmActionDialog"; +import IssueDetailsSummary from "@/components/IssueDetailsSummary"; import ToastViewport from "@/components/ToastViewport"; import { AppInstall, @@ -1043,19 +1044,11 @@ function InstallOperationsModal({ {install.error ? ( -
- {install.error} -
+ ) : null} ) : null} @@ -1852,19 +1845,11 @@ export default function InstalledAppsPage() { {install.error ? ( -
- {install.error} -
+ ) : null}
{error && ( -
- - {error} -
+ )}
) : error ? ( -
- {error} -
+ ) : appDetail ? ( <> {runtimeNotice ? ( -
- Runtime stats are unavailable: {runtimeNotice} -
+ ) : null} {actionError ? ( -
- {actionError} -
+ ) : null} ) : null} {error ? ( -
- {error} -
+ ) : null} {error && ( -
- - {error} -
+ )} diff --git a/src/app/servers/components/ServerConfigModal.tsx b/src/app/servers/components/ServerConfigModal.tsx index b20ef51..ea25403 100644 --- a/src/app/servers/components/ServerConfigModal.tsx +++ b/src/app/servers/components/ServerConfigModal.tsx @@ -47,6 +47,7 @@ import ServerConfigOverviewPanel from "@/app/servers/components/server-config/Se import ServerConfigServicesPanel from "@/app/servers/components/server-config/ServerConfigServicesPanel"; import ServerConfigUsersPanel from "@/app/servers/components/server-config/ServerConfigUsersPanel"; import ServerConfigWebServerPanel from "@/app/servers/components/server-config/ServerConfigWebServerPanel"; +import IssueDetailsSummary from "@/components/IssueDetailsSummary"; interface ServerConfigModalProps { server: ServerType; @@ -1098,18 +1099,11 @@ export default function ServerConfigModal({ ) : null} {error ? ( -
- {error} -
+ ) : null} {snapshotLoadError ? ( @@ -1140,15 +1134,11 @@ export default function ServerConfigModal({ available, especially in the Actions tab.

-
- Latest error: {snapshotLoadError} -
+
) : null} diff --git a/src/app/users/page.tsx b/src/app/users/page.tsx index 5bdd388..e1178ea 100644 --- a/src/app/users/page.tsx +++ b/src/app/users/page.tsx @@ -2,8 +2,8 @@ import ConfirmActionDialog from "@/components/ConfirmActionDialog"; import GuardedPage from "@/components/GuardedPage"; +import IssueDetailsSummary from "@/components/IssueDetailsSummary"; import ToastViewport from "@/components/ToastViewport"; -import { AlertCircle } from "lucide-react"; import { useCallback, useEffect, useMemo, useState } from "react"; import { CreateUserInvitationBody, @@ -383,21 +383,11 @@ export default function UsersPage() { style={{ display: "flex", flexDirection: "column", gap: 16 }} > {error && ( -
- - {error} -
+ )} diff --git a/src/components/IssueDetailsSummary.tsx b/src/components/IssueDetailsSummary.tsx new file mode 100644 index 0000000..60b7c76 --- /dev/null +++ b/src/components/IssueDetailsSummary.tsx @@ -0,0 +1,92 @@ +"use client"; + +import { useState } from "react"; +import { createPortal } from "react-dom"; +import { AlertTriangle, X } from "lucide-react"; + +type IssueDetailsSummaryProps = { + label: string; + message?: string; + notes?: string[]; + description?: string; +}; + +export default function IssueDetailsSummary({ + label, + message, + notes, + description = "Issue details returned by the current operation.", +}: IssueDetailsSummaryProps) { + const [detailOpen, setDetailOpen] = useState(false); + const issueNotes = (notes?.length ? notes : message ? [message] : []).filter( + Boolean, + ); + const issueCount = issueNotes.length || 1; + + return ( + <> + + + {detailOpen && typeof document !== "undefined" + ? createPortal( +
+
+
+
+ + {label} Issues + +

+ {description} +

+
+ +
+
+ {issueNotes.map((note, index) => ( +
+ {note} +
+ ))} +
+
+
, + document.body, + ) + : null} + + ); +}