mirror of
https://github.com/fosrl/pangolin.git
synced 2026-09-02 01:09:03 +02:00
Merge branch 'dev' into feat/ip-filtering
This commit is contained in:
@@ -79,7 +79,7 @@ function MessageBubble({ message }: { message: NormalizedAiMessage }) {
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={`max-w-[80%] rounded-lg px-3 py-2 text-sm whitespace-pre-wrap break-words ${
|
||||
className={`min-w-0 max-w-[80%] rounded-lg px-3 py-2 text-sm whitespace-pre-wrap break-words ${
|
||||
isUser
|
||||
? "bg-primary text-primary-foreground"
|
||||
: isTool
|
||||
@@ -108,7 +108,7 @@ function RawFallbackBlock({
|
||||
}) {
|
||||
const pretty = prettyRaw(raw);
|
||||
return (
|
||||
<div className="rounded-md border bg-muted/30 p-3">
|
||||
<div className="min-w-0 rounded-md border bg-muted/30 p-3">
|
||||
<div className="mb-1 text-xs font-medium text-muted-foreground">
|
||||
{label}
|
||||
{pretty && unparsedLabel && (
|
||||
@@ -117,7 +117,7 @@ function RawFallbackBlock({
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<pre className="max-h-64 overflow-auto whitespace-pre-wrap break-words text-xs text-muted-foreground">
|
||||
<pre className="max-h-64 overflow-auto whitespace-pre-wrap break-all text-xs text-muted-foreground">
|
||||
{pretty ?? noDataLabel}
|
||||
</pre>
|
||||
</div>
|
||||
@@ -172,7 +172,7 @@ export function AiSessionChatView({
|
||||
</Button>
|
||||
</div>
|
||||
{rawMode ? (
|
||||
<div className="flex max-h-[32rem] flex-col gap-3 overflow-y-auto rounded-md border bg-background p-4">
|
||||
<div className="flex min-w-0 max-h-[32rem] flex-col gap-3 overflow-y-auto rounded-md border bg-background p-4">
|
||||
<RawFallbackBlock
|
||||
label={t("aiSessionRequest")}
|
||||
raw={normalizedRequest}
|
||||
@@ -185,7 +185,7 @@ export function AiSessionChatView({
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex max-h-[32rem] flex-col gap-3 overflow-y-auto rounded-md border bg-background p-4">
|
||||
<div className="flex min-w-0 max-h-[32rem] flex-col gap-3 overflow-y-auto rounded-md border bg-background p-4">
|
||||
{hasRequestMessages ? (
|
||||
requestMessages!.map((message, i) => (
|
||||
<MessageBubble key={`req-${i}`} message={message} />
|
||||
|
||||
@@ -57,6 +57,7 @@ export interface Destination {
|
||||
sendActionLogs: boolean;
|
||||
sendConnectionLogs: boolean;
|
||||
sendRequestLogs: boolean;
|
||||
sendAISessionLogs: boolean;
|
||||
lastError: string | null;
|
||||
lastErrorAt: number | null;
|
||||
createdAt: number;
|
||||
@@ -180,6 +181,7 @@ export function HttpDestinationCredenza({
|
||||
const [sendActionLogs, setSendActionLogs] = useState(false);
|
||||
const [sendConnectionLogs, setSendConnectionLogs] = useState(false);
|
||||
const [sendRequestLogs, setSendRequestLogs] = useState(false);
|
||||
const [sendAISessionLogs, setSendAISessionLogs] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
@@ -190,6 +192,7 @@ export function HttpDestinationCredenza({
|
||||
setSendActionLogs(editing?.sendActionLogs ?? false);
|
||||
setSendConnectionLogs(editing?.sendConnectionLogs ?? false);
|
||||
setSendRequestLogs(editing?.sendRequestLogs ?? false);
|
||||
setSendAISessionLogs(editing?.sendAISessionLogs ?? false);
|
||||
}
|
||||
}, [open, editing]);
|
||||
|
||||
@@ -226,7 +229,8 @@ export function HttpDestinationCredenza({
|
||||
sendAccessLogs,
|
||||
sendActionLogs,
|
||||
sendConnectionLogs,
|
||||
sendRequestLogs
|
||||
sendRequestLogs,
|
||||
sendAISessionLogs
|
||||
};
|
||||
if (editing) {
|
||||
await api.post(
|
||||
@@ -778,6 +782,30 @@ export function HttpDestinationCredenza({
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-3 rounded-md border p-3">
|
||||
<Checkbox
|
||||
id="log-ai-session"
|
||||
checked={sendAISessionLogs}
|
||||
onCheckedChange={(v) =>
|
||||
setSendAISessionLogs(v === true)
|
||||
}
|
||||
className="mt-0.5"
|
||||
/>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="log-ai-session"
|
||||
className="text-sm font-medium cursor-pointer"
|
||||
>
|
||||
{t("httpDestAISessionLogsTitle")}
|
||||
</label>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
{t(
|
||||
"httpDestAISessionLogsDescription"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</HorizontalTabs>
|
||||
|
||||
@@ -313,6 +313,15 @@ export function LogDataTable<TData, TValue>({
|
||||
}
|
||||
}, [currentPage, table, isServerPagination]);
|
||||
|
||||
// Collapse any expanded rows whenever the page changes, since row ids
|
||||
// are reused across pages and would otherwise show the wrong content
|
||||
// in the same expanded position.
|
||||
const pageIndex = table.getState().pagination.pageIndex;
|
||||
useEffect(() => {
|
||||
setExpandedRows(new Set());
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pageIndex]);
|
||||
|
||||
const handleTabChange = (value: string) => {
|
||||
if (disabled) return;
|
||||
|
||||
@@ -515,9 +524,13 @@ export function LogDataTable<TData, TValue>({
|
||||
}
|
||||
className="p-4 bg-muted/50"
|
||||
>
|
||||
{renderExpandedRow(
|
||||
row.original
|
||||
)}
|
||||
{/* w-0 min-w-full keeps this cell's content from */}
|
||||
{/* blowing out the table's auto column widths */}
|
||||
<div className="w-0 min-w-full">
|
||||
{renderExpandedRow(
|
||||
row.original
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
|
||||
@@ -90,6 +90,7 @@ export function S3DestinationCredenza({
|
||||
const [sendActionLogs, setSendActionLogs] = useState(false);
|
||||
const [sendConnectionLogs, setSendConnectionLogs] = useState(false);
|
||||
const [sendRequestLogs, setSendRequestLogs] = useState(false);
|
||||
const [sendAISessionLogs, setSendAISessionLogs] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
@@ -98,6 +99,7 @@ export function S3DestinationCredenza({
|
||||
setSendActionLogs(editing?.sendActionLogs ?? false);
|
||||
setSendConnectionLogs(editing?.sendConnectionLogs ?? false);
|
||||
setSendRequestLogs(editing?.sendRequestLogs ?? false);
|
||||
setSendAISessionLogs(editing?.sendAISessionLogs ?? false);
|
||||
}
|
||||
}, [open, editing]);
|
||||
|
||||
@@ -121,7 +123,8 @@ export function S3DestinationCredenza({
|
||||
sendAccessLogs,
|
||||
sendActionLogs,
|
||||
sendConnectionLogs,
|
||||
sendRequestLogs
|
||||
sendRequestLogs,
|
||||
sendAISessionLogs
|
||||
};
|
||||
if (editing) {
|
||||
await api.post(
|
||||
@@ -510,6 +513,30 @@ export function S3DestinationCredenza({
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-3 rounded-md border p-3">
|
||||
<Checkbox
|
||||
id="s3-log-ai-session"
|
||||
checked={sendAISessionLogs}
|
||||
onCheckedChange={(v) =>
|
||||
setSendAISessionLogs(v === true)
|
||||
}
|
||||
className="mt-0.5"
|
||||
/>
|
||||
<div>
|
||||
<Label
|
||||
htmlFor="s3-log-ai-session"
|
||||
className="cursor-pointer font-medium"
|
||||
>
|
||||
{t("httpDestAISessionLogsTitle")}
|
||||
</Label>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
{t(
|
||||
"httpDestAISessionLogsDescription"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</HorizontalTabs>
|
||||
|
||||
@@ -129,6 +129,7 @@ export function ToggleableTrendChart(props: ToggleableTrendChartProps) {
|
||||
payload?.[0]?.payload?.day
|
||||
)
|
||||
}
|
||||
valueFormatter={valueFormatter}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
@@ -172,6 +173,7 @@ export function ToggleableTrendChart(props: ToggleableTrendChartProps) {
|
||||
payload?.[0]?.payload?.day
|
||||
)
|
||||
}
|
||||
valueFormatter={valueFormatter}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -47,7 +47,8 @@ export function buildSeriesFromData(
|
||||
export const currencyFormatter = new Intl.NumberFormat(undefined, {
|
||||
style: "currency",
|
||||
currency: "USD",
|
||||
maximumFractionDigits: 2
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 4
|
||||
});
|
||||
|
||||
export const compactNumberFormatter = new Intl.NumberFormat(undefined, {
|
||||
|
||||
+16
-10
@@ -135,6 +135,7 @@ type ChartTooltipContentProps = React.ComponentProps<"div"> & {
|
||||
labelKey?: string;
|
||||
color?: string;
|
||||
labelClassName?: string;
|
||||
valueFormatter?: (value: number) => string;
|
||||
};
|
||||
|
||||
const ChartTooltipContent = React.forwardRef<
|
||||
@@ -155,7 +156,8 @@ const ChartTooltipContent = React.forwardRef<
|
||||
formatter,
|
||||
color,
|
||||
nameKey,
|
||||
labelKey
|
||||
labelKey,
|
||||
valueFormatter
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
@@ -302,19 +304,23 @@ const ChartTooltipContent = React.forwardRef<
|
||||
item.name}
|
||||
</span>
|
||||
</div>
|
||||
{item.value && (
|
||||
{item.value !== undefined && (
|
||||
<span className="font-mono font-medium tabular-nums text-foreground">
|
||||
{!isNaN(
|
||||
item.value as number
|
||||
)
|
||||
? new Intl.NumberFormat(
|
||||
navigator.language,
|
||||
{
|
||||
maximumFractionDigits: 0
|
||||
}
|
||||
).format(
|
||||
item.value as number
|
||||
)
|
||||
? valueFormatter
|
||||
? valueFormatter(
|
||||
item.value as number
|
||||
)
|
||||
: new Intl.NumberFormat(
|
||||
navigator.language,
|
||||
{
|
||||
maximumFractionDigits: 0
|
||||
}
|
||||
).format(
|
||||
item.value as number
|
||||
)
|
||||
: item.value.toLocaleString()}
|
||||
</span>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user