mirror of
https://github.com/meta-llama/llama-stack.git
synced 2025-08-15 22:18:00 +00:00
feat(UI): Adding linter and prettier for UI (#3156)
This commit is contained in:
parent
61582f327c
commit
e69acbafbf
73 changed files with 1452 additions and 1226 deletions
|
@ -14,7 +14,7 @@ describe("ChatCompletionDetailView", () => {
|
|||
isLoading={true}
|
||||
error={null}
|
||||
id="test-id"
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
// Use the data-slot attribute for Skeletons
|
||||
const skeletons = container.querySelectorAll('[data-slot="skeleton"]');
|
||||
|
@ -28,10 +28,10 @@ describe("ChatCompletionDetailView", () => {
|
|||
isLoading={false}
|
||||
error={{ name: "Error", message: "Network Error" }}
|
||||
id="err-id"
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
screen.getByText(/Error loading details for ID err-id: Network Error/),
|
||||
screen.getByText(/Error loading details for ID err-id: Network Error/)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
@ -42,11 +42,11 @@ describe("ChatCompletionDetailView", () => {
|
|||
isLoading={false}
|
||||
error={{ name: "Error", message: "" }}
|
||||
id="err-id"
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
// Use regex to match the error message regardless of whitespace
|
||||
expect(
|
||||
screen.getByText(/Error loading details for ID\s*err-id\s*:/),
|
||||
screen.getByText(/Error loading details for ID\s*err-id\s*:/)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
@ -57,11 +57,11 @@ describe("ChatCompletionDetailView", () => {
|
|||
isLoading={false}
|
||||
error={{} as Error}
|
||||
id="err-id"
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
// Use regex to match the error message regardless of whitespace
|
||||
expect(
|
||||
screen.getByText(/Error loading details for ID\s*err-id\s*:/),
|
||||
screen.getByText(/Error loading details for ID\s*err-id\s*:/)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
@ -72,10 +72,10 @@ describe("ChatCompletionDetailView", () => {
|
|||
isLoading={false}
|
||||
error={null}
|
||||
id="notfound-id"
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
screen.getByText("No details found for ID: notfound-id."),
|
||||
screen.getByText("No details found for ID: notfound-id.")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
@ -100,7 +100,7 @@ describe("ChatCompletionDetailView", () => {
|
|||
isLoading={false}
|
||||
error={null}
|
||||
id={mockCompletion.id}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
// Input
|
||||
expect(screen.getByText("Input")).toBeInTheDocument();
|
||||
|
@ -112,7 +112,7 @@ describe("ChatCompletionDetailView", () => {
|
|||
expect(screen.getByText("Properties")).toBeInTheDocument();
|
||||
expect(screen.getByText("Created:")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(new Date(1710000000 * 1000).toLocaleString()),
|
||||
screen.getByText(new Date(1710000000 * 1000).toLocaleString())
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText("ID:")).toBeInTheDocument();
|
||||
expect(screen.getByText("comp_123")).toBeInTheDocument();
|
||||
|
@ -150,7 +150,7 @@ describe("ChatCompletionDetailView", () => {
|
|||
isLoading={false}
|
||||
error={null}
|
||||
id={mockCompletion.id}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
// Output should include the tool call block (should be present twice: input and output)
|
||||
const toolCallLabels = screen.getAllByText("Tool Call");
|
||||
|
@ -178,13 +178,13 @@ describe("ChatCompletionDetailView", () => {
|
|||
isLoading={false}
|
||||
error={null}
|
||||
id={mockCompletion.id}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
// Input section should be present but empty
|
||||
expect(screen.getByText("Input")).toBeInTheDocument();
|
||||
// Output section should show fallback message
|
||||
expect(
|
||||
screen.getByText("No message found in assistant's choice."),
|
||||
screen.getByText("No message found in assistant's choice.")
|
||||
).toBeInTheDocument();
|
||||
// Properties should show N/A for finish reason
|
||||
expect(screen.getByText("Finish Reason:")).toBeInTheDocument();
|
||||
|
|
|
@ -53,14 +53,14 @@ export function ChatCompletionDetailView({
|
|||
{completion.choices?.[0]?.message?.tool_calls &&
|
||||
Array.isArray(completion.choices[0].message.tool_calls) &&
|
||||
!completion.input_messages?.some(
|
||||
(im) =>
|
||||
im =>
|
||||
im.role === "assistant" &&
|
||||
im.tool_calls &&
|
||||
Array.isArray(im.tool_calls) &&
|
||||
im.tool_calls.length > 0,
|
||||
im.tool_calls.length > 0
|
||||
)
|
||||
? completion.choices[0].message.tool_calls.map(
|
||||
(toolCall: any, index: number) => {
|
||||
(toolCall: { function?: { name?: string } }, index: number) => {
|
||||
const assistantToolCallMessage: ChatMessage = {
|
||||
role: "assistant",
|
||||
tool_calls: [toolCall],
|
||||
|
@ -72,7 +72,7 @@ export function ChatCompletionDetailView({
|
|||
message={assistantToolCallMessage}
|
||||
/>
|
||||
);
|
||||
},
|
||||
}
|
||||
)
|
||||
: null}
|
||||
</CardContent>
|
||||
|
@ -89,7 +89,7 @@ export function ChatCompletionDetailView({
|
|||
/>
|
||||
) : (
|
||||
<p className="text-gray-500 italic text-sm">
|
||||
No message found in assistant's choice.
|
||||
No message found in assistant's choice.
|
||||
</p>
|
||||
)}
|
||||
</CardContent>
|
||||
|
@ -120,13 +120,18 @@ export function ChatCompletionDetailView({
|
|||
value={
|
||||
<div>
|
||||
<ul className="list-disc list-inside pl-4 mt-1">
|
||||
{toolCalls.map((toolCall: any, index: number) => (
|
||||
<li key={index}>
|
||||
<span className="text-gray-900 font-medium">
|
||||
{toolCall.function?.name || "N/A"}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
{toolCalls.map(
|
||||
(
|
||||
toolCall: { function?: { name?: string } },
|
||||
index: number
|
||||
) => (
|
||||
<li key={index}>
|
||||
<span className="text-gray-900 font-medium">
|
||||
{toolCall.function?.name || "N/A"}
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ describe("ChatCompletionsTable", () => {
|
|||
// Default pass-through implementations
|
||||
truncateText.mockImplementation((text: string | undefined) => text);
|
||||
extractTextFromContentPart.mockImplementation((content: unknown) =>
|
||||
typeof content === "string" ? content : "extracted text",
|
||||
typeof content === "string" ? content : "extracted text"
|
||||
);
|
||||
extractDisplayableText.mockImplementation((message: unknown) => {
|
||||
const msg = message as { content?: string };
|
||||
|
@ -138,7 +138,7 @@ describe("ChatCompletionsTable", () => {
|
|||
if (row) {
|
||||
fireEvent.click(row);
|
||||
expect(mockPush).toHaveBeenCalledWith(
|
||||
"/logs/chat-completions/completion_123",
|
||||
"/logs/chat-completions/completion_123"
|
||||
);
|
||||
} else {
|
||||
throw new Error('Row with "Test prompt" not found for router mock test.');
|
||||
|
@ -162,7 +162,7 @@ describe("ChatCompletionsTable", () => {
|
|||
expect(tableCaption).toBeInTheDocument();
|
||||
if (tableCaption) {
|
||||
const captionSkeleton = tableCaption.querySelector(
|
||||
'[data-slot="skeleton"]',
|
||||
'[data-slot="skeleton"]'
|
||||
);
|
||||
expect(captionSkeleton).toBeInTheDocument();
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ describe("ChatCompletionsTable", () => {
|
|||
expect(tableBody).toBeInTheDocument();
|
||||
if (tableBody) {
|
||||
const bodySkeletons = tableBody.querySelectorAll(
|
||||
'[data-slot="skeleton"]',
|
||||
'[data-slot="skeleton"]'
|
||||
);
|
||||
expect(bodySkeletons.length).toBeGreaterThan(0);
|
||||
}
|
||||
|
@ -192,14 +192,14 @@ describe("ChatCompletionsTable", () => {
|
|||
|
||||
render(<ChatCompletionsTable {...defaultProps} />);
|
||||
expect(
|
||||
screen.getByText("Unable to load chat completions"),
|
||||
screen.getByText("Unable to load chat completions")
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText(errorMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test.each([{ name: "Error", message: "" }, {}])(
|
||||
"renders default error message when error has no message",
|
||||
(errorObject) => {
|
||||
errorObject => {
|
||||
mockedUsePagination.mockReturnValue({
|
||||
data: [],
|
||||
status: "error",
|
||||
|
@ -210,14 +210,14 @@ describe("ChatCompletionsTable", () => {
|
|||
|
||||
render(<ChatCompletionsTable {...defaultProps} />);
|
||||
expect(
|
||||
screen.getByText("Unable to load chat completions"),
|
||||
screen.getByText("Unable to load chat completions")
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
"An unexpected error occurred while loading the data.",
|
||||
),
|
||||
"An unexpected error occurred while loading the data."
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -225,7 +225,7 @@ describe("ChatCompletionsTable", () => {
|
|||
test('renders "No chat completions found." and no table when data array is empty', () => {
|
||||
render(<ChatCompletionsTable {...defaultProps} />);
|
||||
expect(
|
||||
screen.getByText("No chat completions found."),
|
||||
screen.getByText("No chat completions found.")
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Ensure that the table structure is NOT rendered in the empty state
|
||||
|
@ -292,7 +292,7 @@ describe("ChatCompletionsTable", () => {
|
|||
|
||||
// Table caption
|
||||
expect(
|
||||
screen.getByText("A list of your recent chat completions."),
|
||||
screen.getByText("A list of your recent chat completions.")
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Table headers
|
||||
|
@ -306,14 +306,14 @@ describe("ChatCompletionsTable", () => {
|
|||
expect(screen.getByText("Test output")).toBeInTheDocument();
|
||||
expect(screen.getByText("llama-test-model")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(new Date(1710000000 * 1000).toLocaleString()),
|
||||
screen.getByText(new Date(1710000000 * 1000).toLocaleString())
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText("Another input")).toBeInTheDocument();
|
||||
expect(screen.getByText("Another output")).toBeInTheDocument();
|
||||
expect(screen.getByText("llama-another-model")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(new Date(1710001000 * 1000).toLocaleString()),
|
||||
screen.getByText(new Date(1710001000 * 1000).toLocaleString())
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -328,7 +328,7 @@ describe("ChatCompletionsTable", () => {
|
|||
return typeof text === "string" && text.length > effectiveMaxLength
|
||||
? text.slice(0, effectiveMaxLength) + "..."
|
||||
: text;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const longInput =
|
||||
|
@ -368,7 +368,7 @@ describe("ChatCompletionsTable", () => {
|
|||
|
||||
// The truncated text should be present for both input and output
|
||||
const truncatedTexts = screen.getAllByText(
|
||||
longInput.slice(0, 10) + "...",
|
||||
longInput.slice(0, 10) + "..."
|
||||
);
|
||||
expect(truncatedTexts.length).toBe(2); // one for input, one for output
|
||||
});
|
||||
|
@ -420,7 +420,7 @@ describe("ChatCompletionsTable", () => {
|
|||
// Verify the extracted text appears in the table
|
||||
expect(screen.getByText("Extracted input")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("Extracted output from assistant"),
|
||||
screen.getByText("Extracted output from assistant")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
UsePaginationOptions,
|
||||
ListChatCompletionsResponse,
|
||||
} from "@/lib/types";
|
||||
import { ListChatCompletionsParams } from "@/lib/llama-stack-client";
|
||||
import { LogsTable, LogTableRow } from "@/components/logs/logs-table";
|
||||
import {
|
||||
extractTextFromContentPart,
|
||||
|
@ -38,14 +39,14 @@ export function ChatCompletionsTable({
|
|||
limit: number;
|
||||
model?: string;
|
||||
order?: string;
|
||||
},
|
||||
}
|
||||
) => {
|
||||
const response = await client.chat.completions.list({
|
||||
after: params.after,
|
||||
limit: params.limit,
|
||||
...(params.model && { model: params.model }),
|
||||
...(params.order && { order: params.order }),
|
||||
} as any);
|
||||
} as ListChatCompletionsParams);
|
||||
|
||||
return response as ListChatCompletionsResponse;
|
||||
};
|
||||
|
|
|
@ -37,21 +37,26 @@ export function ChatMessageItem({ message }: ChatMessageItemProps) {
|
|||
) {
|
||||
return (
|
||||
<>
|
||||
{message.tool_calls.map((toolCall: any, index: number) => {
|
||||
const formattedToolCall = formatToolCallToString(toolCall);
|
||||
const toolCallContent = (
|
||||
<ToolCallBlock>
|
||||
{formattedToolCall || "Error: Could not display tool call"}
|
||||
</ToolCallBlock>
|
||||
);
|
||||
return (
|
||||
<MessageBlock
|
||||
key={index}
|
||||
label="Tool Call"
|
||||
content={toolCallContent}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{message.tool_calls.map(
|
||||
(
|
||||
toolCall: { function?: { name?: string; arguments?: unknown } },
|
||||
index: number
|
||||
) => {
|
||||
const formattedToolCall = formatToolCallToString(toolCall);
|
||||
const toolCallContent = (
|
||||
<ToolCallBlock>
|
||||
{formattedToolCall || "Error: Could not display tool call"}
|
||||
</ToolCallBlock>
|
||||
);
|
||||
return (
|
||||
<MessageBlock
|
||||
key={index}
|
||||
label="Tool Call"
|
||||
content={toolCallContent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue