Przeglądaj źródła

feat(dashboard): standardize session status labels to 4-letter format

- Change status labels: ERROR->FAIL, IN_PROGRESS->BUSY, INITIALIZING->INIT
- Add status column to active-sessions-table with visual indicators
- Maintain consistent styling between live-sessions-panel and sessions table

Co-Authored-By: Claude Opus 4.5 <[email protected]>
ding113 3 tygodni temu
rodzic
commit
2976216271

+ 3 - 3
src/app/[locale]/dashboard/_components/bento/live-sessions-panel.tsx

@@ -36,7 +36,7 @@ function SessionItem({ session }: { session: ActiveSessionInfo }) {
   // Determine ping animation color based on status
   // Determine ping animation color based on status
   const getPingColor = (info: SessionStatusInfo) => {
   const getPingColor = (info: SessionStatusInfo) => {
     if (info.status === SESSION_DISPLAY_STATUS.IN_PROGRESS) {
     if (info.status === SESSION_DISPLAY_STATUS.IN_PROGRESS) {
-      return info.label === "ERROR" ? "bg-rose-500" : "bg-emerald-500";
+      return info.label === "FAIL" ? "bg-rose-500" : "bg-emerald-500";
     }
     }
     if (info.status === SESSION_DISPLAY_STATUS.INITIALIZING) {
     if (info.status === SESSION_DISPLAY_STATUS.INITIALIZING) {
       return "bg-amber-500";
       return "bg-amber-500";
@@ -47,7 +47,7 @@ function SessionItem({ session }: { session: ActiveSessionInfo }) {
   // Determine user name color based on status
   // Determine user name color based on status
   const getUserNameColor = (info: SessionStatusInfo) => {
   const getUserNameColor = (info: SessionStatusInfo) => {
     if (info.status === SESSION_DISPLAY_STATUS.IN_PROGRESS) {
     if (info.status === SESSION_DISPLAY_STATUS.IN_PROGRESS) {
-      return info.label === "ERROR"
+      return info.label === "FAIL"
         ? "text-rose-500 dark:text-rose-400"
         ? "text-rose-500 dark:text-rose-400"
         : "text-blue-500 dark:text-blue-400";
         : "text-blue-500 dark:text-blue-400";
     }
     }
@@ -78,7 +78,7 @@ function SessionItem({ session }: { session: ActiveSessionInfo }) {
             style={{ animationDuration: "1.5s" }}
             style={{ animationDuration: "1.5s" }}
           />
           />
         )}
         )}
-        {statusInfo.label === "ERROR" ? (
+        {statusInfo.label === "FAIL" ? (
           <XCircle className={cn("h-2.5 w-2.5 relative", statusInfo.color)} fill="currentColor" />
           <XCircle className={cn("h-2.5 w-2.5 relative", statusInfo.color)} fill="currentColor" />
         ) : (
         ) : (
           <Circle className={cn("h-2.5 w-2.5 relative", statusInfo.color)} fill="currentColor" />
           <Circle className={cn("h-2.5 w-2.5 relative", statusInfo.color)} fill="currentColor" />

+ 73 - 2
src/app/[locale]/dashboard/sessions/_components/active-sessions-table.tsx

@@ -1,6 +1,6 @@
 "use client";
 "use client";
 
 
-import { Eye, XCircle } from "lucide-react";
+import { Circle, Eye, XCircle } from "lucide-react";
 import { useTranslations } from "next-intl";
 import { useTranslations } from "next-intl";
 import { useEffect, useMemo, useState } from "react";
 import { useEffect, useMemo, useState } from "react";
 import { toast } from "sonner";
 import { toast } from "sonner";
@@ -27,7 +27,12 @@ import {
   TableHeader,
   TableHeader,
   TableRow,
   TableRow,
 } from "@/components/ui/table";
 } from "@/components/ui/table";
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
 import { Link } from "@/i18n/routing";
 import { Link } from "@/i18n/routing";
+import {
+  getSessionDisplayStatus,
+  SESSION_DISPLAY_STATUS,
+} from "@/lib/session-status";
 import { cn } from "@/lib/utils";
 import { cn } from "@/lib/utils";
 import type { CurrencyCode } from "@/lib/utils/currency";
 import type { CurrencyCode } from "@/lib/utils/currency";
 import { formatCurrency } from "@/lib/utils/currency";
 import { formatCurrency } from "@/lib/utils/currency";
@@ -55,6 +60,68 @@ function formatDuration(durationMs: number | undefined): string {
   }
   }
 }
 }
 
 
+function SessionStatusCell({
+  session,
+  inactive,
+}: {
+  session: ActiveSessionInfo;
+  inactive?: boolean;
+}) {
+  const t = useTranslations("customs.activeSessions");
+  const statusInfo = getSessionDisplayStatus({
+    concurrentCount: inactive ? 0 : session.concurrentCount,
+    requestCount: session.requestCount,
+    status: session.status,
+  });
+
+  const StatusIcon =
+    statusInfo.label === "FAIL" ? XCircle : Circle;
+
+  return (
+    <TooltipProvider delayDuration={300}>
+      <Tooltip>
+        <TooltipTrigger asChild>
+          <div className="inline-flex items-center gap-1.5 cursor-help">
+            <div className="relative">
+              {statusInfo.pulse && (
+                <span
+                  className={cn(
+                    "absolute inset-0 rounded-full animate-ping opacity-75",
+                    statusInfo.status === SESSION_DISPLAY_STATUS.IN_PROGRESS
+                      ? statusInfo.label === "FAIL"
+                        ? "bg-rose-500"
+                        : "bg-emerald-500"
+                      : statusInfo.status === SESSION_DISPLAY_STATUS.INITIALIZING
+                        ? "bg-amber-500"
+                        : ""
+                  )}
+                  style={{ animationDuration: "1.5s" }}
+                />
+              )}
+              <StatusIcon
+                className={cn("h-2.5 w-2.5 relative", statusInfo.color)}
+                fill="currentColor"
+              />
+            </div>
+            <span
+              className={cn(
+                "text-xs font-mono font-bold tracking-wide",
+                statusInfo.color,
+                statusInfo.status === SESSION_DISPLAY_STATUS.IDLE && "font-normal"
+              )}
+            >
+              {statusInfo.label}
+            </span>
+          </div>
+        </TooltipTrigger>
+        <TooltipContent side="top" className="max-w-[200px]">
+          <p className="text-xs">{t(statusInfo.tooltipKey)}</p>
+        </TooltipContent>
+      </Tooltip>
+    </TooltipProvider>
+  );
+}
+
 export function ActiveSessionsTable({
 export function ActiveSessionsTable({
   sessions,
   sessions,
   isLoading,
   isLoading,
@@ -190,7 +257,7 @@ export function ActiveSessionsTable({
     }
     }
   };
   };
 
 
-  const totalColumns = showSelection ? 12 : 11;
+  const totalColumns = showSelection ? 13 : 12;
   const showLoadingRows = isLoading && sessions.length === 0;
   const showLoadingRows = isLoading && sessions.length === 0;
   const allSelected =
   const allSelected =
     showSelection &&
     showSelection &&
@@ -269,6 +336,7 @@ export function ActiveSessionsTable({
                 </TableHead>
                 </TableHead>
               )}
               )}
               <TableHead>{t("columns.sessionId")}</TableHead>
               <TableHead>{t("columns.sessionId")}</TableHead>
+              <TableHead className="text-center">{t("columns.status")}</TableHead>
               <TableHead>{t("columns.user")}</TableHead>
               <TableHead>{t("columns.user")}</TableHead>
               <TableHead>{t("columns.key")}</TableHead>
               <TableHead>{t("columns.key")}</TableHead>
               <TableHead>{t("columns.provider")}</TableHead>
               <TableHead>{t("columns.provider")}</TableHead>
@@ -316,6 +384,9 @@ export function ActiveSessionsTable({
                   <TableCell className="font-mono text-xs">
                   <TableCell className="font-mono text-xs">
                     {session.sessionId.substring(0, 16)}...
                     {session.sessionId.substring(0, 16)}...
                   </TableCell>
                   </TableCell>
+                  <TableCell className="text-center">
+                    <SessionStatusCell session={session} inactive={inactive} />
+                  </TableCell>
                   <TableCell>{session.userName}</TableCell>
                   <TableCell>{session.userName}</TableCell>
                   <TableCell className="font-mono text-xs">{session.keyName}</TableCell>
                   <TableCell className="font-mono text-xs">{session.keyName}</TableCell>
                   <TableCell
                   <TableCell

+ 4 - 4
src/lib/session-status.ts

@@ -53,7 +53,7 @@ export function getSessionDisplayStatus(session: SessionStatusInput): SessionSta
   if (status === "error") {
   if (status === "error") {
     return {
     return {
       status: SESSION_DISPLAY_STATUS.IN_PROGRESS,
       status: SESSION_DISPLAY_STATUS.IN_PROGRESS,
-      label: "ERROR",
+      label: "FAIL",
       tooltipKey: "status.errorTooltip",
       tooltipKey: "status.errorTooltip",
       color: "text-rose-500 dark:text-rose-400",
       color: "text-rose-500 dark:text-rose-400",
       pulse: true,
       pulse: true,
@@ -64,7 +64,7 @@ export function getSessionDisplayStatus(session: SessionStatusInput): SessionSta
   if (requestCount <= 1 && concurrentCount > 0) {
   if (requestCount <= 1 && concurrentCount > 0) {
     return {
     return {
       status: SESSION_DISPLAY_STATUS.INITIALIZING,
       status: SESSION_DISPLAY_STATUS.INITIALIZING,
-      label: SESSION_DISPLAY_STATUS.INITIALIZING,
+      label: "INIT",
       tooltipKey: "status.initializingTooltip",
       tooltipKey: "status.initializingTooltip",
       color: "text-amber-500 dark:text-amber-400",
       color: "text-amber-500 dark:text-amber-400",
       pulse: true,
       pulse: true,
@@ -75,7 +75,7 @@ export function getSessionDisplayStatus(session: SessionStatusInput): SessionSta
   if (concurrentCount > 0) {
   if (concurrentCount > 0) {
     return {
     return {
       status: SESSION_DISPLAY_STATUS.IN_PROGRESS,
       status: SESSION_DISPLAY_STATUS.IN_PROGRESS,
-      label: SESSION_DISPLAY_STATUS.IN_PROGRESS,
+      label: "BUSY",
       tooltipKey: "status.inProgressTooltip",
       tooltipKey: "status.inProgressTooltip",
       color: "text-emerald-500 dark:text-emerald-400",
       color: "text-emerald-500 dark:text-emerald-400",
       pulse: true,
       pulse: true,
@@ -85,7 +85,7 @@ export function getSessionDisplayStatus(session: SessionStatusInput): SessionSta
   // IDLE: no active requests
   // IDLE: no active requests
   return {
   return {
     status: SESSION_DISPLAY_STATUS.IDLE,
     status: SESSION_DISPLAY_STATUS.IDLE,
-    label: SESSION_DISPLAY_STATUS.IDLE,
+    label: "IDLE",
     tooltipKey: "status.idleTooltip",
     tooltipKey: "status.idleTooltip",
     color: "text-muted-foreground/50",
     color: "text-muted-foreground/50",
     pulse: false,
     pulse: false,