Răsfoiți Sursa

refactor(logs): redesign origin decision section with StepCard layout

ding113 3 zile în urmă
părinte
comite
dab5cd5ea6

+ 127 - 49
src/app/[locale]/dashboard/logs/_components/error-details-dialog/components/LogicTraceTab.tsx

@@ -338,65 +338,143 @@ export function LogicTraceTab({
                   originChain &&
                   originChain.length > 0 &&
                   (() => {
-                    const originItem =
-                      originChain.find((item) => item.reason === "initial_selection") ??
-                      originChain[0];
+                    const originItem = originChain.find(
+                      (item) => item.reason === "initial_selection"
+                    );
                     const ctx = originItem?.decisionContext;
+                    const originFilteredProviders = originChain.flatMap(
+                      (item) => item.decisionContext?.filteredProviders || []
+                    );
                     return (
-                      <div className="space-y-2 px-2 py-1 text-xs">
-                        <div className="font-medium text-muted-foreground">
+                      <div className="space-y-2 px-2 py-1">
+                        <div className="text-xs font-medium text-muted-foreground">
                           {t("logicTrace.originDecisionTitle")}
                         </div>
                         {ctx && (
-                          <div className="grid grid-cols-2 gap-1.5 pl-2 min-w-0">
-                            <div>
-                              <span className="text-muted-foreground">
-                                {t("logicTrace.providersCount", { count: ctx.totalProviders })}
-                              </span>
-                            </div>
-                            {ctx.enabledProviders !== undefined && (
-                              <div>
-                                <span className="text-muted-foreground">
-                                  {t("logicTrace.providersCount", { count: ctx.enabledProviders })}
-                                </span>
-                              </div>
-                            )}
-                            {ctx.afterHealthCheck !== undefined && (
-                              <div>
-                                <span className="text-muted-foreground">
-                                  {tChain("details.afterHealthCheck")}:
-                                </span>{" "}
-                                <span className="font-mono">{ctx.afterHealthCheck}</span>
-                              </div>
-                            )}
-                            {ctx.selectedPriority !== undefined && (
-                              <div>
-                                <span className="text-muted-foreground">
-                                  {tChain("details.priority")}:
-                                </span>{" "}
-                                <span className="font-mono">P{ctx.selectedPriority}</span>
+                          <StepCard
+                            step={1}
+                            icon={Database}
+                            title={t("logicTrace.initialSelection")}
+                            subtitle={`${ctx.totalProviders} -> ${ctx.afterModelFilter || ctx.afterHealthCheck}`}
+                            status="success"
+                            details={
+                              <div className="grid grid-cols-2 gap-2 text-xs min-w-0">
+                                <div className="min-w-0">
+                                  <span className="text-muted-foreground">Total:</span>{" "}
+                                  <span className="font-mono">{ctx.totalProviders}</span>
+                                </div>
+                                <div className="min-w-0">
+                                  <span className="text-muted-foreground">Enabled:</span>{" "}
+                                  <span className="font-mono">{ctx.enabledProviders}</span>
+                                </div>
+                                {ctx.afterGroupFilter !== undefined && (
+                                  <div className="min-w-0">
+                                    <span className="text-muted-foreground">After Group:</span>{" "}
+                                    <span className="font-mono">{ctx.afterGroupFilter}</span>
+                                  </div>
+                                )}
+                                {ctx.afterModelFilter !== undefined && (
+                                  <div className="min-w-0">
+                                    <span className="text-muted-foreground">After Model:</span>{" "}
+                                    <span className="font-mono">{ctx.afterModelFilter}</span>
+                                  </div>
+                                )}
                               </div>
-                            )}
-                            {ctx.candidatesAtPriority && ctx.candidatesAtPriority.length > 0 && (
-                              <div className="col-span-2">
-                                <span className="text-muted-foreground">
-                                  {tChain("details.candidates")}:
-                                </span>{" "}
-                                {ctx.candidatesAtPriority.map((c, i) => (
-                                  <span key={c.id}>
-                                    {i > 0 && ", "}
-                                    {c.name}
-                                    {c.probability !== undefined && (
-                                      <span className="text-muted-foreground">
-                                        {" "}
-                                        {formatProbability(c.probability)}
+                            }
+                          />
+                        )}
+                        {originFilteredProviders.length > 0 && (
+                          <StepCard
+                            step={2}
+                            icon={Filter}
+                            title={t("logicTrace.healthCheck")}
+                            subtitle={`${originFilteredProviders.length} providers filtered`}
+                            status="warning"
+                            details={
+                              <div className="space-y-1 min-w-0">
+                                {originFilteredProviders.map((p, idx) => (
+                                  <div
+                                    key={`${p.id}-${idx}`}
+                                    className="flex items-center gap-2 text-xs flex-wrap min-w-0"
+                                  >
+                                    <Badge
+                                      variant="outline"
+                                      className="text-[10px] shrink-0 max-w-[120px] truncate"
+                                    >
+                                      {p.name}
+                                    </Badge>
+                                    <span className="text-rose-600 break-all">
+                                      {tChain(`filterReasons.${p.reason}`)}
+                                    </span>
+                                    {p.details && (
+                                      <span className="text-muted-foreground break-all">
+                                        (
+                                        {tChain.has(`filterDetails.${p.details}`)
+                                          ? tChain(`filterDetails.${p.details}`)
+                                          : p.details}
+                                        )
                                       </span>
                                     )}
-                                  </span>
+                                  </div>
                                 ))}
                               </div>
-                            )}
-                          </div>
+                            }
+                          />
+                        )}
+                        {ctx?.priorityLevels && ctx.priorityLevels.length > 0 && (
+                          <StepCard
+                            step={originFilteredProviders.length > 0 ? 3 : 2}
+                            icon={Layers}
+                            title={t("logicTrace.prioritySelection")}
+                            subtitle={`Priority ${ctx.selectedPriority}`}
+                            status="success"
+                            details={
+                              <div className="space-y-2">
+                                <div className="flex gap-1 flex-wrap">
+                                  {ctx.priorityLevels.map((p) => (
+                                    <Badge
+                                      key={p}
+                                      variant={p === ctx?.selectedPriority ? "default" : "outline"}
+                                      className="text-[10px]"
+                                    >
+                                      P{p}
+                                    </Badge>
+                                  ))}
+                                </div>
+                                {ctx.candidatesAtPriority &&
+                                  ctx.candidatesAtPriority.length > 0 && (
+                                    <div className="space-y-1 mt-2">
+                                      {ctx.candidatesAtPriority.map((c, idx) => {
+                                        const formattedProbability = formatProbability(
+                                          c.probability
+                                        );
+                                        return (
+                                          <div
+                                            key={`${c.id}-${idx}`}
+                                            className="flex items-center justify-between text-xs"
+                                          >
+                                            <span className="font-medium">{c.name}</span>
+                                            <div className="flex items-center gap-2">
+                                              <span className="text-muted-foreground">
+                                                W:{c.weight}
+                                              </span>
+                                              <span className="text-muted-foreground">
+                                                x{c.costMultiplier}
+                                              </span>
+                                              {formattedProbability && (
+                                                <Badge variant="secondary" className="text-[10px]">
+                                                  {formattedProbability}
+                                                </Badge>
+                                              )}
+                                            </div>
+                                          </div>
+                                        );
+                                      })}
+                                    </div>
+                                  )}
+                              </div>
+                            }
+                          />
                         )}
                       </div>
                     );