* feat(settings): add rxresume mode and v5 api key settings * feat(server): add mode-aware rxresume adapter with auto v5-first selection * refactor(server): route settings profile and pdf generation through rxresume adapter * feat(api): support rxresume v4/v5 in onboarding and settings routes with ok/meta responses * feat(client): add rxresume mode selector and v5 api key setup flow * docs: document rxresume auto mode with v5-first self-hosted setup * test: verify dual-mode rxresume support and ci parity checks * comments * services folder * correct types for v5 * tests and docs fix * Fix RxResume auto fallback and route API consistency * warning for both being set * simpler response * onboarding component improvements, v5 check still not working * fix list resume endpoint... * fix api endpoints to latest v5 docs * don't show the entire project field on v5 * remove auto entirely * formatting * ci green * v5 has a different resume schema * remove redundant check * remove requirement that only one must be specified * consolidate sections * base resume can be v4 or v5 * saving now works * status indicator * actually render some pills * reason for failure * fix apikey verification * dedupe isValidatingMode * reefactoor * simplification? * refactor? * ci passing * remove auto from docs * tailoring is schema dependent * skills object tighter * remove redundant text * fix lint * mode
122 lines
3.2 KiB
TypeScript
122 lines
3.2 KiB
TypeScript
import type { JobStatus } from "@shared/types/jobs";
|
|
import type React from "react";
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
TooltipTrigger,
|
|
} from "@/components/ui/tooltip";
|
|
import { cn } from "@/lib/utils";
|
|
import {
|
|
defaultStatusToken,
|
|
statusTokens,
|
|
} from "../pages/orchestrator/constants";
|
|
|
|
const STATUS_INDICATOR_BASE_CLASS =
|
|
"inline-flex items-center gap-1.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground/80";
|
|
const STATUS_INDICATOR_DOT_CLASS = "h-1.5 w-1.5 rounded-full opacity-80";
|
|
|
|
const badgeVariantClasses = {
|
|
amber: {
|
|
badge: "border-amber-500/30 bg-amber-500/10 text-amber-200",
|
|
dot: "bg-amber-400",
|
|
},
|
|
emerald: {
|
|
badge: "border-emerald-500/30 bg-emerald-500/10 text-emerald-200",
|
|
dot: "bg-emerald-400",
|
|
},
|
|
sky: {
|
|
badge: "border-sky-500/30 bg-sky-500/10 text-sky-200",
|
|
dot: "bg-sky-400",
|
|
},
|
|
};
|
|
|
|
type StatusIndicatorProps = {
|
|
dotColor?: string;
|
|
label: React.ReactNode;
|
|
className?: string;
|
|
dotClassName?: string;
|
|
variant?: keyof typeof badgeVariantClasses;
|
|
appearance?: "inline" | "badge";
|
|
animateDot?: boolean;
|
|
tooltip?: React.ReactNode;
|
|
tooltipClassName?: string;
|
|
tooltipSide?: "top" | "right" | "bottom" | "left";
|
|
tooltipDelayDuration?: number;
|
|
};
|
|
|
|
const StatusIndicator: React.FC<StatusIndicatorProps> = ({
|
|
dotColor,
|
|
label,
|
|
className,
|
|
dotClassName,
|
|
variant = "amber",
|
|
appearance = "inline",
|
|
animateDot = appearance === "badge",
|
|
tooltip,
|
|
tooltipClassName,
|
|
tooltipSide = "top",
|
|
tooltipDelayDuration = 0,
|
|
}) => {
|
|
const badgeTokens = badgeVariantClasses[variant];
|
|
const resolvedDotColor = dotColor ?? badgeTokens.dot;
|
|
|
|
const content = (
|
|
<span
|
|
className={cn(
|
|
appearance === "badge"
|
|
? "inline-flex items-center gap-2 rounded-full border px-2 py-1 text-[11px] font-semibold uppercase tracking-wide"
|
|
: STATUS_INDICATOR_BASE_CLASS,
|
|
appearance === "badge" ? badgeTokens.badge : undefined,
|
|
className,
|
|
)}
|
|
>
|
|
<span
|
|
className={cn(
|
|
appearance === "badge"
|
|
? "h-1.5 w-1.5 rounded-full"
|
|
: STATUS_INDICATOR_DOT_CLASS,
|
|
animateDot ? "animate-pulse" : undefined,
|
|
resolvedDotColor,
|
|
dotClassName,
|
|
)}
|
|
/>
|
|
{label}
|
|
</span>
|
|
);
|
|
|
|
if (!tooltip) return content;
|
|
|
|
return (
|
|
<TooltipProvider>
|
|
<Tooltip delayDuration={tooltipDelayDuration}>
|
|
<TooltipTrigger asChild>{content}</TooltipTrigger>
|
|
<TooltipContent side={tooltipSide} className={tooltipClassName}>
|
|
{tooltip}
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</TooltipProvider>
|
|
);
|
|
};
|
|
|
|
const getJobStatusIndicator = (status: JobStatus) => {
|
|
const tokens = statusTokens[status] ?? defaultStatusToken;
|
|
return { label: tokens.label, dotColor: tokens.dot };
|
|
};
|
|
|
|
const getTracerStatusIndicator = (enabled: boolean) => ({
|
|
label: enabled ? "Tracer On" : "Tracer Off",
|
|
dotColor: enabled ? "bg-violet-500" : "bg-slate-500",
|
|
});
|
|
|
|
const StatusBadgeIndicator: React.FC<
|
|
Omit<StatusIndicatorProps, "appearance"> & { appearance?: "badge" }
|
|
> = (props) => <StatusIndicator {...props} appearance="badge" />;
|
|
|
|
export {
|
|
StatusIndicator,
|
|
getJobStatusIndicator,
|
|
getTracerStatusIndicator,
|
|
StatusBadgeIndicator,
|
|
};
|