Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions web-common/src/features/dashboards/pivot/PivotError.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
<script lang="ts">
import CopyIcon from "@rilldata/web-common/components/icons/CopyIcon.svelte";
import { copyToClipboard } from "@rilldata/web-common/lib/actions/copy-to-clipboard";
import type { PivotQueryError } from "./types";
export let errors: PivotQueryError[];
const MAX_ERROR_LENGTH = 500;
function removeDuplicates(errors: PivotQueryError[]): PivotQueryError[] {
const seen = new Set();
return errors.filter((error) => {
Expand All @@ -16,21 +20,59 @@
});
}
function truncateMessage(message: string): string {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use css directly for max width?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSS would work well with single line text for choose this option for multiline content. Using line-clamp could also be a bit tricky at places depending on the layout.

if (message.length <= MAX_ERROR_LENGTH) {
return message;
}
return message.slice(0, MAX_ERROR_LENGTH) + "...";
}
function handleCopyError(error: PivotQueryError) {
const fullError = `${error.statusCode}${error.traceId ? ` (Trace ID: ${error.traceId})` : ""}: ${error.message}`;
copyToClipboard(fullError, "Error message copied to clipboard");
}
function getUniqueTraceIds(errors: PivotQueryError[]): string[] {
const traceIds = errors
.map((error) => error.traceId)
.filter((id): id is string => id !== undefined && id !== null);
return [...new Set(traceIds)];
}
$: traceIds = getUniqueTraceIds(errors);
let uniqueErrors = removeDuplicates(errors);
</script>

<div class="flex flex-col items-center w-full h-full">
<span class="text-3xl font-normal m-2">Sorry, unexpected query error!</span>
{#if traceIds.length > 0}
<div class="text-sm ui-copy mt-1">
<b>Trace ID{traceIds.length !== 1 ? "s" : ""}</b>: {traceIds.join(", ")}
</div>
{/if}
<div class="text-base text-gray-600 mt-4">
One or more APIs failed with the following error{uniqueErrors.length !== 1
? "s"
: ""}:
</div>

{#each uniqueErrors as error}
<div class="flex text-base gap-x-2">
<span class="text-red-600 font-semibold">{error.statusCode} :</span>
<span class="text-gray-800">{error.message}</span>
<div class="flex text-base gap-x-2 items-start max-w-4xl">
<span class="text-red-600 font-semibold whitespace-nowrap"
>{error.statusCode}:</span
>
<span class="text-gray-800 flex-1 break-words">
{truncateMessage(error.message ?? "")}
</span>
<button
class="flex-shrink-0 p-1 hover:bg-gray-100 rounded transition-colors cursor-pointer"
on:click={() => handleCopyError(error)}
title="Copy full error message"
aria-label="Copy error message to clipboard"
>
<CopyIcon size="16px" color="#6B7280" />
</button>
</div>
{/each}
</div>
1 change: 1 addition & 0 deletions web-common/src/features/dashboards/pivot/pivot-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ export function getErrorFromResponse(
return {
statusCode: queryResult?.error?.response?.status || null,
message: queryResult?.error?.response?.data?.message,
traceId: queryResult?.error?.traceId,
};
}

Expand Down
1 change: 1 addition & 0 deletions web-common/src/features/dashboards/pivot/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export interface PivotTimeConfig {
export interface PivotQueryError {
statusCode: number | null;
message?: string;
traceId?: string;
}

/**
Expand Down
6 changes: 6 additions & 0 deletions web-common/src/runtime-client/fetchWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface HTTPError {
};
message: string;
name: string;
traceId?: string;
}

export function isHTTPError(error: unknown): error is HTTPError {
Expand Down Expand Up @@ -69,18 +70,23 @@ export async function fetchWrapper({

if (resp.ok) return json;

// Extract trace ID from response headers
const traceId = resp.headers?.get("x-trace-id");

// Return runtime errors in the same form as the Axios client had previously
if (json?.code && json?.message) {
return Promise.reject({
response: {
status: resp.status,
data: json,
},
traceId,
});
} else {
// Fallback error handling
const err = new Error();
(err as any).response = json;
(err as any).traceId = traceId;
return Promise.reject(err);
}
}
Expand Down
Loading