mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
refactor(ui): codemod every toast call site onto lib/toast and delete the antd-era facades (#37253)
MessageManager and NotificationManager were thin facades over lib/toast since #37207. This rewrites their ~750 call sites (226 files) to import { toast } from @/lib/toast directly: success/info/warning/error keep their names, fromBackend becomes fromError, destroy/clear become dismiss. The one config-object caller (CreateMCPServer's admin-review branch) becomes an explicit toast.success(message, { description }). Behaviour is unchanged: no production caller passed a duration, so every toast keeps the same kind, title and default duration. Tests: the global vitest mock now targets @/lib/toast (toast.test.ts opts back out with vi.unmock), so the per-file vi.mock boilerplate for the facades is deleted and assertions read toast.success / toast.fromError. The two facade files, their test and their filename-case suppressions are removed, along with the commented-out facade calls left in networking.tsx
This commit is contained in:
parent
8159f240c4
commit
83ae623733
246 changed files with 1042 additions and 1679 deletions
|
|
@ -2497,16 +2497,6 @@
|
|||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/molecules/message_manager.tsx": {
|
||||
"local/filename-pascal-case": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/molecules/notifications_manager.tsx": {
|
||||
"local/filename-pascal-case": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/components/navbar.tsx": {
|
||||
"local/filename-pascal-case": {
|
||||
"count": 1
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Modal, Form } from "antd";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { AccessGroupBaseForm, AccessGroupFormValues } from "./AccessGroupBaseForm";
|
||||
import { useEditAccessGroup, AccessGroupUpdateParams } from "@/app/(dashboard)/hooks/accessGroups/useEditAccessGroup";
|
||||
import { AccessGroupResponse } from "@/app/(dashboard)/hooks/accessGroups/useAccessGroups";
|
||||
|
|
@ -45,7 +45,7 @@ export function AccessGroupEditModal({ visible, accessGroup, onCancel, onSuccess
|
|||
{ accessGroupId: accessGroup.access_group_id, params },
|
||||
{
|
||||
onSuccess: () => {
|
||||
MessageManager.success("Access group updated successfully");
|
||||
toast.success("Access group updated successfully");
|
||||
onSuccess?.();
|
||||
onCancel();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@ import userEvent from "@testing-library/user-event";
|
|||
import React from "react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
__esModule: true,
|
||||
default: { success: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
vi.mock("@/components/ModelSelect/ModelSelect", () => ({
|
||||
ModelSelect: ({ onChange }: { onChange: (values: string[]) => void }) => (
|
||||
<button type="button" onClick={() => onChange(["gpt-5.2"])}>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { accessGroupKeys } from "@/app/(dashboard)/hooks/accessGroups/useAccessG
|
|||
import { useAgents } from "@/app/(dashboard)/hooks/agents/useAgents";
|
||||
import { useMCPServers } from "@/app/(dashboard)/hooks/mcpServers/useMCPServers";
|
||||
import { ModelSelect } from "@/components/ModelSelect/ModelSelect";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { FieldGroup } from "@/components/shared/form/field";
|
||||
import { FormField } from "@/components/shared/form/FormField";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
|
@ -113,12 +113,12 @@ export const AccessGroupCreateDialog = ({
|
|||
const mutation = useMutation({
|
||||
mutationFn: (body: AccessGroupCreateBody) => createAccessGroup(body),
|
||||
onSuccess: () => {
|
||||
NotificationsManager.success("Access group created successfully");
|
||||
toast.success("Access group created successfully");
|
||||
queryClient.invalidateQueries({ queryKey: accessGroupKeys.all });
|
||||
closeAndReset();
|
||||
},
|
||||
onError: (error: unknown) =>
|
||||
NotificationsManager.fromBackend(error instanceof Error ? error.message : "Failed to create access group"),
|
||||
toast.fromError(error instanceof Error ? error.message : "Failed to create access group"),
|
||||
});
|
||||
|
||||
const handleOpenChange = (nextOpen: boolean) => {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { Alert, Button as Button2, Form, Input, Modal, Space, Tabs, Typography }
|
|||
import React, { useEffect, useState } from "react";
|
||||
import NewBadge from "@/components/common_components/NewBadge";
|
||||
import { useBaseUrl } from "@/components/constants";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { addAllowedIP, deleteAllowedIP, getAllowedIPs, getSSOSettings } from "@/components/networking";
|
||||
import SCIMConfig from "@/components/SCIM";
|
||||
import LoggingSettings from "@/components/Settings/AdminSettings/LoggingSettings/LoggingSettings";
|
||||
|
|
@ -79,9 +79,7 @@ const AdminPanel: React.FC<AdminPanelProps> = ({ proxySettings }) => {
|
|||
const handleShowAllowedIPs = async () => {
|
||||
try {
|
||||
if (premiumUser !== true) {
|
||||
NotificationsManager.fromBackend(
|
||||
"This feature is only available for premium users. Please upgrade your account.",
|
||||
);
|
||||
toast.fromError("This feature is only available for premium users. Please upgrade your account.");
|
||||
return;
|
||||
}
|
||||
if (accessToken) {
|
||||
|
|
@ -92,7 +90,7 @@ const AdminPanel: React.FC<AdminPanelProps> = ({ proxySettings }) => {
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching allowed IPs:", error);
|
||||
NotificationsManager.fromBackend(`Failed to fetch allowed IPs ${error}`);
|
||||
toast.fromError(`Failed to fetch allowed IPs ${error}`);
|
||||
setAllowedIPs([all_ip_address_allowed]);
|
||||
} finally {
|
||||
if (premiumUser === true) {
|
||||
|
|
@ -108,11 +106,11 @@ const AdminPanel: React.FC<AdminPanelProps> = ({ proxySettings }) => {
|
|||
// Fetch the updated list of IPs
|
||||
const updatedIPs = await getAllowedIPs(accessToken);
|
||||
setAllowedIPs(updatedIPs);
|
||||
NotificationsManager.success("IP address added successfully");
|
||||
toast.success("IP address added successfully");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error adding IP:", error);
|
||||
NotificationsManager.fromBackend(`Failed to add IP address ${error}`);
|
||||
toast.fromError(`Failed to add IP address ${error}`);
|
||||
} finally {
|
||||
setIsAddIPModalVisible(false);
|
||||
}
|
||||
|
|
@ -130,10 +128,10 @@ const AdminPanel: React.FC<AdminPanelProps> = ({ proxySettings }) => {
|
|||
// Fetch the updated list of IPs
|
||||
const updatedIPs = await getAllowedIPs(accessToken);
|
||||
setAllowedIPs(updatedIPs.length > 0 ? updatedIPs : [all_ip_address_allowed]);
|
||||
NotificationsManager.success("IP address deleted successfully");
|
||||
toast.success("IP address deleted successfully");
|
||||
} catch (error) {
|
||||
console.error("Error deleting IP:", error);
|
||||
NotificationsManager.fromBackend(`Failed to delete IP address ${error}`);
|
||||
toast.fromError(`Failed to delete IP address ${error}`);
|
||||
} finally {
|
||||
setIsDeleteIPModalVisible(false);
|
||||
setIPToDelete(null);
|
||||
|
|
@ -229,7 +227,7 @@ const AdminPanel: React.FC<AdminPanelProps> = ({ proxySettings }) => {
|
|||
onClick={() =>
|
||||
premiumUser === true
|
||||
? setIsUIAccessControlModalVisible(true)
|
||||
: NotificationsManager.fromBackend("Only premium users can configure UI access control")
|
||||
: toast.fromError("Only premium users can configure UI access control")
|
||||
}
|
||||
>
|
||||
UI Access Control
|
||||
|
|
@ -335,7 +333,7 @@ const AdminPanel: React.FC<AdminPanelProps> = ({ proxySettings }) => {
|
|||
accessToken={accessToken}
|
||||
onSuccess={() => {
|
||||
handleUIAccessControlOk();
|
||||
NotificationsManager.success("UI Access Control settings updated successfully");
|
||||
toast.success("UI Access Control settings updated successfully");
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import AddAgentForm from "./add_agent_form";
|
|||
import { isAdminRole } from "@/utils/roles";
|
||||
import AgentInfoView from "./agent_info";
|
||||
import AgentsTable from "./AgentsTable";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Agent } from "@/components/agents/types";
|
||||
import { Team } from "@/components/key_team_helpers/key_list";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/shared/Alert";
|
||||
|
|
@ -120,11 +120,11 @@ const AgentsPanel: React.FC<AgentsPanelProps> = ({ accessToken, userRole, teams
|
|||
setIsDeleting(true);
|
||||
try {
|
||||
await deleteAgentCall(accessToken, agentToDelete.id);
|
||||
NotificationsManager.success(`Agent "${agentToDelete.name}" deleted successfully`);
|
||||
toast.success(`Agent "${agentToDelete.name}" deleted successfully`);
|
||||
await refetchAgents(healthCheckEnabled);
|
||||
} catch (error) {
|
||||
console.error("Error deleting agent:", error);
|
||||
NotificationsManager.fromBackend("Failed to delete agent");
|
||||
toast.fromError("Failed to delete agent");
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
setAgentToDelete(null);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Modal, Form, Select, Input, Steps, Radio, Tag, Divider, Switch, InputNumber } from "antd";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Logo } from "@/components/molecules/logo/Logo";
|
||||
import { Button } from "@tremor/react";
|
||||
import { CheckCircleFilled, KeyOutlined, RobotOutlined, AppstoreOutlined, InfoCircleOutlined } from "@ant-design/icons";
|
||||
|
|
@ -241,7 +241,7 @@ const AddAgentForm: React.FC<AddAgentFormProps> = ({ visible, onClose, accessTok
|
|||
|
||||
const handleCreateAgent = async () => {
|
||||
if (!accessToken) {
|
||||
MessageManager.error("No access token available");
|
||||
toast.error("No access token available");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ const AddAgentForm: React.FC<AddAgentFormProps> = ({ visible, onClose, accessTok
|
|||
const values = { ...form.getFieldsValue(true) };
|
||||
const agentData = buildAgentData(values);
|
||||
if (!agentData) {
|
||||
MessageManager.error("Failed to build agent data");
|
||||
toast.error("Failed to build agent data");
|
||||
setIsSubmitting(false);
|
||||
return;
|
||||
}
|
||||
|
|
@ -327,7 +327,7 @@ const AddAgentForm: React.FC<AddAgentFormProps> = ({ visible, onClose, accessTok
|
|||
setCreatedKeyValue(keyResponse.key || null);
|
||||
} else if (keyAssignOption === "existing_key") {
|
||||
if (!selectedExistingKey) {
|
||||
MessageManager.error("Please select an existing key to assign");
|
||||
toast.error("Please select an existing key to assign");
|
||||
setIsSubmitting(false);
|
||||
return;
|
||||
}
|
||||
|
|
@ -344,7 +344,7 @@ const AddAgentForm: React.FC<AddAgentFormProps> = ({ visible, onClose, accessTok
|
|||
} catch (error) {
|
||||
console.error("Error creating agent:", error);
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
MessageManager.error(errorMessage ? `Failed to create agent: ${errorMessage}` : "Failed to create agent");
|
||||
toast.error(errorMessage ? `Failed to create agent: ${errorMessage}` : "Failed to create agent");
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import { Card, Title, Text, Button as TremorButton, Tab, TabGroup, TabList, TabPanel, TabPanels } from "@tremor/react";
|
||||
import { Form, Input, InputNumber, Button as AntButton, Spin, Descriptions, Divider } from "antd";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { ArrowLeftIcon } from "@heroicons/react/outline";
|
||||
import { getAgentInfo, patchAgentCall, getAgentCreateMetadata, AgentCreateInfo } from "@/components/networking";
|
||||
import { Agent } from "@/components/agents/types";
|
||||
|
|
@ -80,7 +80,7 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching agent info:", error);
|
||||
MessageManager.error("Failed to load agent information");
|
||||
toast.error("Failed to load agent information");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
@ -160,12 +160,12 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
|
|||
}
|
||||
|
||||
await patchAgentCall(accessToken, agentId, updateData);
|
||||
MessageManager.success("Agent updated successfully");
|
||||
toast.success("Agent updated successfully");
|
||||
setIsEditing(false);
|
||||
fetchAgentInfo();
|
||||
} catch (error) {
|
||||
console.error("Error updating agent:", error);
|
||||
MessageManager.error("Failed to update agent");
|
||||
toast.error("Failed to update agent");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Modal } from "antd";
|
|||
import { z } from "zod/v4";
|
||||
import { useCreateBudget } from "@/app/(dashboard)/hooks/budgets/useBudgets";
|
||||
import { applyBudgetPrecision } from "./budgetPrecision";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { FieldGroup } from "@/components/shared/form/field";
|
||||
import { FormField } from "@/components/shared/form/FormField";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
|
@ -52,18 +52,18 @@ const BudgetModal: React.FC<BudgetModalProps> = ({ isModalVisible, setIsModalVis
|
|||
|
||||
const handleCreate = async (formValues: BudgetFormValues) => {
|
||||
try {
|
||||
NotificationsManager.info("Making API Call");
|
||||
toast.info("Making API Call");
|
||||
await createBudget.mutateAsync(
|
||||
applyBudgetPrecision(
|
||||
optionalSettingsOpen ? formValues : { ...formValues, max_budget: undefined, budget_duration: undefined },
|
||||
),
|
||||
);
|
||||
NotificationsManager.success("Budget Created");
|
||||
toast.success("Budget Created");
|
||||
form.reset();
|
||||
setIsModalVisible(false);
|
||||
} catch (error) {
|
||||
console.error("Error creating the budget:", error);
|
||||
NotificationsManager.fromBackend(`Error creating the budget: ${error}`);
|
||||
toast.fromError(`Error creating the budget: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,10 +25,6 @@ vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({
|
|||
default: () => ({ accessToken: "sk-test", userRole: "Admin", userId: "u1" }),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: { success: vi.fn(), info: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
interface BudgetSeed {
|
||||
budget_id: string;
|
||||
max_budget: number | null;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { ToolbarSeparator } from "@/components/shared/ToolbarSeparator";
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { useBudgetList, useDeleteBudget, budgetItem } from "@/app/(dashboard)/hooks/budgets/useBudgets";
|
||||
import BudgetModal from "./budget_modal";
|
||||
import BudgetTable from "./BudgetTable";
|
||||
|
|
@ -60,14 +60,10 @@ const BudgetPanel: React.FC<BudgetSettingsPageProps> = ({ accessToken }) => {
|
|||
}
|
||||
try {
|
||||
await deleteBudget.mutateAsync(selectedBudget.budget_id);
|
||||
NotificationsManager.success("Budget deleted.");
|
||||
toast.success("Budget deleted.");
|
||||
} catch (error) {
|
||||
console.error("Error deleting budget:", error);
|
||||
if (typeof NotificationsManager.fromBackend === "function") {
|
||||
NotificationsManager.fromBackend("Failed to delete budget");
|
||||
} else {
|
||||
NotificationsManager.info("Failed to delete budget");
|
||||
}
|
||||
toast.fromError("Failed to delete budget");
|
||||
} finally {
|
||||
setIsDeleteModalVisible(false);
|
||||
setSelectedBudget(null);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { useForm } from "react-hook-form";
|
|||
import { useUpdateBudget } from "@/app/(dashboard)/hooks/budgets/useBudgets";
|
||||
import { budgetItem } from "@/app/(dashboard)/hooks/budgets/useBudgets";
|
||||
import { applyBudgetPrecision } from "./budgetPrecision";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { FieldGroup } from "@/components/shared/form/field";
|
||||
import { FormField } from "@/components/shared/form/FormField";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
|
@ -58,18 +58,18 @@ const EditBudgetModal: React.FC<EditBudgetModalProps> = ({ isModalVisible, setIs
|
|||
|
||||
const handleUpdate = async (formValues: EditBudgetFormValues) => {
|
||||
try {
|
||||
NotificationsManager.info("Making API Call");
|
||||
toast.info("Making API Call");
|
||||
await updateBudget.mutateAsync(
|
||||
applyBudgetPrecision(
|
||||
optionalSettingsOpen ? formValues : { ...formValues, max_budget: undefined, budget_duration: undefined },
|
||||
),
|
||||
);
|
||||
NotificationsManager.success("Budget Updated");
|
||||
toast.success("Budget Updated");
|
||||
form.reset();
|
||||
setIsModalVisible(false);
|
||||
} catch (error) {
|
||||
console.error("Error updating the budget:", error);
|
||||
NotificationsManager.fromBackend(`Error updating the budget: ${error}`);
|
||||
toast.fromError(`Error updating the budget: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { DateRangePickerValue } from "@/components/shared/date_picker_types";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import UsageDatePicker from "@/components/shared/usage_date_picker";
|
||||
import { BarChart } from "@/components/shared/charts";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
|
@ -104,7 +104,7 @@ const CacheDashboard: React.FC<CachePageProps> = ({ accessToken, token, userRole
|
|||
|
||||
const runCachingHealthCheck = async () => {
|
||||
try {
|
||||
NotificationsManager.info("Running cache health check...");
|
||||
toast.info("Running cache health check...");
|
||||
setHealthCheckResponse("");
|
||||
const response = await cachingHealthCheckCall(accessToken !== null ? accessToken : "");
|
||||
setHealthCheckResponse(response);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Button, Accordion, AccordionHeader, AccordionBody } from "@tremor/react
|
|||
import { Form } from "antd";
|
||||
import { getCacheSettingsCall, testCacheConnectionCall, updateCacheSettingsCall } from "@/components/networking";
|
||||
import { fetchAvailableModels, ModelGroup } from "@/components/llm_calls/fetch_models";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import RedisTypeSelector from "./RedisTypeSelector";
|
||||
import CacheFieldSection from "./CacheFieldSection";
|
||||
import { EmbeddingModelOption } from "./CacheFormField";
|
||||
|
|
@ -39,7 +39,7 @@ const CacheSettings: React.FC<CacheSettingsProps> = ({ accessToken }) => {
|
|||
setRedisType(toRedisType(currentValues.redis_type));
|
||||
} catch (error) {
|
||||
console.error("Failed to load cache settings:", error);
|
||||
NotificationsManager.fromBackend("Failed to load cache settings");
|
||||
toast.fromError("Failed to load cache settings");
|
||||
}
|
||||
}, [accessToken, form]);
|
||||
|
||||
|
|
@ -86,15 +86,13 @@ const CacheSettings: React.FC<CacheSettingsProps> = ({ accessToken }) => {
|
|||
buildCachePayload(redisType, values, { forTesting: true }),
|
||||
);
|
||||
if (result.status === "success") {
|
||||
NotificationsManager.success("Cache connection test successful!");
|
||||
toast.success("Cache connection test successful!");
|
||||
} else {
|
||||
NotificationsManager.fromBackend(`Connection test failed: ${result.message || result.error}`);
|
||||
toast.fromError(`Connection test failed: ${result.message || result.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Test connection error:", error);
|
||||
NotificationsManager.fromBackend(
|
||||
`Connection test failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||
);
|
||||
toast.fromError(`Connection test failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
||||
} finally {
|
||||
setIsTesting(false);
|
||||
}
|
||||
|
|
@ -112,11 +110,11 @@ const CacheSettings: React.FC<CacheSettingsProps> = ({ accessToken }) => {
|
|||
setIsSaving(true);
|
||||
try {
|
||||
await updateCacheSettingsCall(accessToken, buildCachePayload(redisType, values, { forTesting: false }));
|
||||
NotificationsManager.success("Cache settings updated successfully");
|
||||
toast.success("Cache settings updated successfully");
|
||||
await loadCacheSettings();
|
||||
} catch (error) {
|
||||
console.error("Failed to save cache settings:", error);
|
||||
NotificationsManager.fromBackend("Failed to update cache settings");
|
||||
toast.fromError("Failed to update cache settings");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import userEvent from "@testing-library/user-event";
|
|||
import CoordinationRedisSettings from "./index";
|
||||
import { REDACTED_VALUE } from "./types";
|
||||
import * as networking from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
getCoordinationRedisSettingsCall: vi.fn(),
|
||||
|
|
@ -17,14 +17,10 @@ vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({
|
|||
default: () => ({ accessToken: "sk-test" }),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: { success: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
const getSettings = vi.mocked(networking.getCoordinationRedisSettingsCall);
|
||||
const updateSettings = vi.mocked(networking.updateCoordinationRedisSettingsCall);
|
||||
const testConnection = vi.mocked(networking.testCoordinationRedisConnectionCall);
|
||||
const notifications = vi.mocked(NotificationsManager);
|
||||
const notifications = vi.mocked(toast);
|
||||
|
||||
const settingsResponse = (
|
||||
values: Record<string, unknown>,
|
||||
|
|
@ -238,7 +234,7 @@ describe("CoordinationRedisSettings", () => {
|
|||
await user.click(screen.getByRole("button", { name: /test connection/i }));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(notifications.fromBackend).toHaveBeenCalledWith(expect.stringContaining("connection refused")),
|
||||
expect(notifications.fromError).toHaveBeenCalledWith(expect.stringContaining("connection refused")),
|
||||
);
|
||||
expect(notifications.success).not.toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { Button, Form } from "antd";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { StatusBadge } from "@/components/shared/table_cells/status_badge";
|
||||
import {
|
||||
useCoordinationRedisSettings,
|
||||
|
|
@ -37,7 +37,7 @@ const CoordinationRedisSettings: React.FC = () => {
|
|||
|
||||
useEffect(() => {
|
||||
if (isError) {
|
||||
NotificationsManager.fromBackend("Failed to load coordination Redis settings");
|
||||
toast.fromError("Failed to load coordination Redis settings");
|
||||
}
|
||||
}, [isError]);
|
||||
|
||||
|
|
@ -58,14 +58,12 @@ const CoordinationRedisSettings: React.FC = () => {
|
|||
try {
|
||||
const result = await testConnection.mutateAsync(buildCoordinationPayload(redisType, values));
|
||||
if (result.status === "healthy") {
|
||||
NotificationsManager.success("Coordination Redis connection test successful!");
|
||||
toast.success("Coordination Redis connection test successful!");
|
||||
} else {
|
||||
NotificationsManager.fromBackend(`Connection test failed: ${result.error ?? "Unknown error"}`);
|
||||
toast.fromError(`Connection test failed: ${result.error ?? "Unknown error"}`);
|
||||
}
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend(
|
||||
`Connection test failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||
);
|
||||
toast.fromError(`Connection test failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -77,9 +75,9 @@ const CoordinationRedisSettings: React.FC = () => {
|
|||
|
||||
try {
|
||||
await updateSettings.mutateAsync(buildCoordinationPayload(redisType, values));
|
||||
NotificationsManager.success("Coordination Redis settings saved. Restart the proxy to apply them.");
|
||||
toast.success("Coordination Redis settings saved. Restart the proxy to apply them.");
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Failed to update coordination Redis settings");
|
||||
toast.fromError("Failed to update coordination Redis settings");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { getGeneralSettingsCall } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import {
|
||||
PromptCachingPanel,
|
||||
generalSettingsItem,
|
||||
|
|
@ -27,7 +27,7 @@ const PromptCachingTab: React.FC<PromptCachingTabProps> = ({ accessToken, activi
|
|||
.then((data: generalSettingsItem[]) => setSettings(data))
|
||||
.catch((error) => {
|
||||
console.error("Failed to load prompt caching settings:", error);
|
||||
NotificationsManager.fromBackend("Failed to load prompt caching settings");
|
||||
toast.fromError("Failed to load prompt caching settings");
|
||||
});
|
||||
}, [accessToken]);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Button, Form, Input, Switch } from "antd";
|
|||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { createGuardrailCall, getGuardrailsList } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import {
|
||||
buildCompressionGuardrailPayload,
|
||||
compressionGuardrailsOf,
|
||||
|
|
@ -37,7 +37,7 @@ const PromptCompressionTab: React.FC<PromptCompressionTabProps> = ({ accessToken
|
|||
.then((response) => setGuardrails(compressionGuardrailsOf(response as GuardrailListResponse)))
|
||||
.catch((error) => {
|
||||
console.error("Failed to load compression guardrails:", error);
|
||||
NotificationsManager.fromBackend("Failed to load compression guardrails");
|
||||
toast.fromError("Failed to load compression guardrails");
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
}, [accessToken]);
|
||||
|
|
@ -60,12 +60,12 @@ const PromptCompressionTab: React.FC<PromptCompressionTabProps> = ({ accessToken
|
|||
defaultOn: values.defaultOn ?? true,
|
||||
}),
|
||||
);
|
||||
NotificationsManager.success("Compression guardrail created");
|
||||
toast.success("Compression guardrail created");
|
||||
form.resetFields();
|
||||
await loadGuardrails();
|
||||
} catch (error) {
|
||||
console.error("Failed to create compression guardrail:", error);
|
||||
NotificationsManager.fromBackend("Failed to create compression guardrail");
|
||||
toast.fromError("Failed to create compression guardrail");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("@/lib/http/api", () => ({ $api: { useQuery: vi.fn() }, fetchClient: { POST: vi.fn() } }));
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({ default: { fromBackend: vi.fn() } }));
|
||||
|
||||
import { shadowEvalListPollMs, shadowEvalPollMs } from "./useShadowEval";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useMutation, useQueryClient, type QueryClient } from "@tanstack/react-query";
|
||||
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { $api, fetchClient } from "@/lib/http/api";
|
||||
|
||||
import type { components } from "@/lib/http/schema";
|
||||
|
|
@ -60,7 +60,7 @@ const useShadowEvalMutation = <TVariables>(mutationFn: (variables: TVariables) =
|
|||
return useMutation({
|
||||
mutationFn,
|
||||
onSuccess: () => invalidateShadowEval(queryClient),
|
||||
onError: (error: unknown) => NotificationsManager.fromBackend(error),
|
||||
onError: (error: unknown) => toast.fromError(error),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { renderHook, act } from "@testing-library/react";
|
||||
import { useDiscountConfig } from "./use_discount_config";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
getProxyBaseUrl: vi.fn(() => ""),
|
||||
|
|
@ -70,7 +70,7 @@ describe("useDiscountConfig", () => {
|
|||
await result.current.fetchDiscountConfig();
|
||||
});
|
||||
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(expect.stringMatching(/failed to fetch/i));
|
||||
expect(toast.fromError).toHaveBeenCalledWith(expect.stringMatching(/failed to fetch/i));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -84,9 +84,7 @@ describe("useDiscountConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(false);
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(
|
||||
"Please select a provider and enter discount percentage",
|
||||
);
|
||||
expect(toast.fromError).toHaveBeenCalledWith("Please select a provider and enter discount percentage");
|
||||
});
|
||||
|
||||
it("should return false and notify when no discount is provided", async () => {
|
||||
|
|
@ -98,9 +96,7 @@ describe("useDiscountConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(false);
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(
|
||||
"Please select a provider and enter discount percentage",
|
||||
);
|
||||
expect(toast.fromError).toHaveBeenCalledWith("Please select a provider and enter discount percentage");
|
||||
});
|
||||
|
||||
it("should return false and notify when the discount exceeds 100", async () => {
|
||||
|
|
@ -112,7 +108,7 @@ describe("useDiscountConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(false);
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(expect.stringMatching(/0%.*100%/i));
|
||||
expect(toast.fromError).toHaveBeenCalledWith(expect.stringMatching(/0%.*100%/i));
|
||||
});
|
||||
|
||||
it("should return false and notify when the provider already exists in the config", async () => {
|
||||
|
|
@ -135,7 +131,7 @@ describe("useDiscountConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(false);
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(expect.stringMatching(/already exists/i));
|
||||
expect(toast.fromError).toHaveBeenCalledWith(expect.stringMatching(/already exists/i));
|
||||
});
|
||||
|
||||
it("should save the config and return true on a valid new provider", async () => {
|
||||
|
|
@ -156,7 +152,7 @@ describe("useDiscountConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(true);
|
||||
expect(NotificationsManager.success).toHaveBeenCalledWith("Discount configuration updated successfully");
|
||||
expect(toast.success).toHaveBeenCalledWith("Discount configuration updated successfully");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState, useCallback } from "react";
|
||||
import { getProxyBaseUrl, getGlobalLitellmHeaderName } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { DiscountConfig } from "./types";
|
||||
import { getProviderBackendValue } from "./provider_display_helpers";
|
||||
import { Providers } from "@/components/provider_info_helpers";
|
||||
|
|
@ -43,7 +43,7 @@ export function useDiscountConfig({ accessToken }: UseDiscountConfigProps): UseD
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching discount config:", error);
|
||||
NotificationsManager.fromBackend("Failed to fetch discount configuration");
|
||||
toast.fromError("Failed to fetch discount configuration");
|
||||
}
|
||||
}, [accessToken]);
|
||||
|
||||
|
|
@ -63,16 +63,16 @@ export function useDiscountConfig({ accessToken }: UseDiscountConfigProps): UseD
|
|||
});
|
||||
|
||||
if (response.ok) {
|
||||
NotificationsManager.success("Discount configuration updated successfully");
|
||||
toast.success("Discount configuration updated successfully");
|
||||
await fetchDiscountConfig();
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
const errorMessage = errorData.detail?.error || errorData.detail || "Failed to update settings";
|
||||
NotificationsManager.fromBackend(errorMessage);
|
||||
toast.fromError(errorMessage);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating discount config:", error);
|
||||
NotificationsManager.fromBackend("Failed to update discount configuration");
|
||||
toast.fromError("Failed to update discount configuration");
|
||||
}
|
||||
},
|
||||
[accessToken, fetchDiscountConfig],
|
||||
|
|
@ -81,25 +81,25 @@ export function useDiscountConfig({ accessToken }: UseDiscountConfigProps): UseD
|
|||
const handleAddProvider = useCallback(
|
||||
async (selectedProvider: string | undefined, newDiscount: string): Promise<boolean> => {
|
||||
if (!selectedProvider || !newDiscount) {
|
||||
NotificationsManager.fromBackend("Please select a provider and enter discount percentage");
|
||||
toast.fromError("Please select a provider and enter discount percentage");
|
||||
return false;
|
||||
}
|
||||
|
||||
const percentageValue = parseFloat(newDiscount);
|
||||
if (isNaN(percentageValue) || percentageValue < 0 || percentageValue > 100) {
|
||||
NotificationsManager.fromBackend("Discount must be between 0% and 100%");
|
||||
toast.fromError("Discount must be between 0% and 100%");
|
||||
return false;
|
||||
}
|
||||
|
||||
const providerValue = getProviderBackendValue(selectedProvider);
|
||||
|
||||
if (!providerValue) {
|
||||
NotificationsManager.fromBackend("Invalid provider selected");
|
||||
toast.fromError("Invalid provider selected");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (discountConfig[providerValue]) {
|
||||
NotificationsManager.fromBackend(
|
||||
toast.fromError(
|
||||
`Discount for ${Providers[selectedProvider as keyof typeof Providers]} already exists. Edit it in the table above.`,
|
||||
);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { renderHook, act } from "@testing-library/react";
|
||||
import { useMarginConfig } from "./use_margin_config";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
getProxyBaseUrl: vi.fn(() => ""),
|
||||
|
|
@ -70,7 +70,7 @@ describe("useMarginConfig", () => {
|
|||
await result.current.fetchMarginConfig();
|
||||
});
|
||||
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(expect.stringMatching(/failed to fetch/i));
|
||||
expect(toast.fromError).toHaveBeenCalledWith(expect.stringMatching(/failed to fetch/i));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ describe("useMarginConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(false);
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith("Please select a provider");
|
||||
expect(toast.fromError).toHaveBeenCalledWith("Please select a provider");
|
||||
});
|
||||
|
||||
it("should return false and notify when percentage is out of range", async () => {
|
||||
|
|
@ -106,7 +106,7 @@ describe("useMarginConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(false);
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(expect.stringMatching(/0%.*1000%/i));
|
||||
expect(toast.fromError).toHaveBeenCalledWith(expect.stringMatching(/0%.*1000%/i));
|
||||
});
|
||||
|
||||
it("should return false when the provider already has a margin configured", async () => {
|
||||
|
|
@ -134,7 +134,7 @@ describe("useMarginConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(false);
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(expect.stringMatching(/already exists/i));
|
||||
expect(toast.fromError).toHaveBeenCalledWith(expect.stringMatching(/already exists/i));
|
||||
});
|
||||
|
||||
it("should save a percentage margin and return true for a valid new provider", async () => {
|
||||
|
|
@ -160,7 +160,7 @@ describe("useMarginConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(true);
|
||||
expect(NotificationsManager.success).toHaveBeenCalledWith("Margin configuration updated successfully");
|
||||
expect(toast.success).toHaveBeenCalledWith("Margin configuration updated successfully");
|
||||
});
|
||||
|
||||
it("should save a fixed amount margin and return true for a valid new provider", async () => {
|
||||
|
|
@ -189,7 +189,7 @@ describe("useMarginConfig", () => {
|
|||
});
|
||||
|
||||
expect(success!).toBe(true);
|
||||
expect(NotificationsManager.success).toHaveBeenCalledWith("Margin configuration updated successfully");
|
||||
expect(toast.success).toHaveBeenCalledWith("Margin configuration updated successfully");
|
||||
});
|
||||
|
||||
it("should accept the global provider without provider_map lookup", async () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState, useCallback } from "react";
|
||||
import { getProxyBaseUrl, getGlobalLitellmHeaderName } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { MarginConfig } from "./types";
|
||||
import { getProviderBackendValue } from "./provider_display_helpers";
|
||||
import { Providers } from "@/components/provider_info_helpers";
|
||||
|
|
@ -53,7 +53,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching margin config:", error);
|
||||
NotificationsManager.fromBackend("Failed to fetch margin configuration");
|
||||
toast.fromError("Failed to fetch margin configuration");
|
||||
}
|
||||
}, [accessToken]);
|
||||
|
||||
|
|
@ -73,16 +73,16 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
});
|
||||
|
||||
if (response.ok) {
|
||||
NotificationsManager.success("Margin configuration updated successfully");
|
||||
toast.success("Margin configuration updated successfully");
|
||||
await fetchMarginConfig();
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
const errorMessage = errorData.detail?.error || errorData.detail || "Failed to update settings";
|
||||
NotificationsManager.fromBackend(errorMessage);
|
||||
toast.fromError(errorMessage);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating margin config:", error);
|
||||
NotificationsManager.fromBackend("Failed to update margin configuration");
|
||||
toast.fromError("Failed to update margin configuration");
|
||||
}
|
||||
},
|
||||
[accessToken, fetchMarginConfig],
|
||||
|
|
@ -93,7 +93,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
const { selectedProvider, marginType, percentageValue, fixedAmountValue } = params;
|
||||
|
||||
if (!selectedProvider) {
|
||||
NotificationsManager.fromBackend("Please select a provider");
|
||||
toast.fromError("Please select a provider");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
} else {
|
||||
const backendValue = getProviderBackendValue(selectedProvider);
|
||||
if (!backendValue) {
|
||||
NotificationsManager.fromBackend("Invalid provider selected");
|
||||
toast.fromError("Invalid provider selected");
|
||||
return false;
|
||||
}
|
||||
providerValue = backendValue;
|
||||
|
|
@ -112,7 +112,7 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
if (marginConfig[providerValue]) {
|
||||
const displayName =
|
||||
providerValue === "global" ? "Global" : Providers[selectedProvider as keyof typeof Providers];
|
||||
NotificationsManager.fromBackend(`Margin for ${displayName} already exists. Edit it in the table above.`);
|
||||
toast.fromError(`Margin for ${displayName} already exists. Edit it in the table above.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -120,14 +120,14 @@ export function useMarginConfig({ accessToken }: UseMarginConfigProps): UseMargi
|
|||
if (marginType === "percentage") {
|
||||
const percentValue = parseFloat(percentageValue);
|
||||
if (isNaN(percentValue) || percentValue < 0 || percentValue > 1000) {
|
||||
NotificationsManager.fromBackend("Percentage must be between 0% and 1000%");
|
||||
toast.fromError("Percentage must be between 0% and 1000%");
|
||||
return false;
|
||||
}
|
||||
marginValue = percentValue / 100;
|
||||
} else {
|
||||
const fixedValue = parseFloat(fixedAmountValue);
|
||||
if (isNaN(fixedValue) || fixedValue < 0) {
|
||||
NotificationsManager.fromBackend("Fixed amount must be non-negative");
|
||||
toast.fromError("Fixed amount must be non-negative");
|
||||
return false;
|
||||
}
|
||||
marginValue = { fixed_amount: fixedValue };
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from "react";
|
||||
import { Copy, Info } from "lucide-react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
|
|
@ -45,14 +45,14 @@ export function GuardrailTestPanel({
|
|||
|
||||
const handleSubmit = () => {
|
||||
if (!inputText.trim()) {
|
||||
NotificationsManager.fromBackend("Please enter text to test");
|
||||
toast.fromError("Please enter text to test");
|
||||
return;
|
||||
}
|
||||
|
||||
const { metadata, error } = parseMetadata(metadataText);
|
||||
if (error) {
|
||||
setMetadataError(error);
|
||||
NotificationsManager.fromBackend(`Metadata: ${error}`);
|
||||
toast.fromError(`Metadata: ${error}`);
|
||||
return;
|
||||
}
|
||||
setMetadataError(null);
|
||||
|
|
@ -98,9 +98,9 @@ export function GuardrailTestPanel({
|
|||
const handleCopyInput = async () => {
|
||||
const success = await copyToClipboard(inputText);
|
||||
if (success) {
|
||||
NotificationsManager.success("Input copied to clipboard");
|
||||
toast.success("Input copied to clipboard");
|
||||
} else {
|
||||
NotificationsManager.fromBackend("Failed to copy input");
|
||||
toast.fromError("Failed to copy input");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useState } from "react";
|
|||
import { FlaskConical, Search } from "lucide-react";
|
||||
import GuardrailTestPanel from "./GuardrailTestPanel";
|
||||
import { applyGuardrail } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/ui/input-group";
|
||||
import { UiLoadingSpinner } from "@/components/ui/ui-loading-spinner";
|
||||
|
|
@ -105,10 +105,10 @@ const GuardrailTestPlayground: React.FC<GuardrailTestPlaygroundProps> = ({
|
|||
setIsTesting(false);
|
||||
|
||||
if (results.length > 0) {
|
||||
NotificationsManager.success(`${results.length} guardrail${results.length > 1 ? "s" : ""} applied successfully`);
|
||||
toast.success(`${results.length} guardrail${results.length > 1 ? "s" : ""} applied successfully`);
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
NotificationsManager.fromBackend(`${errors.length} guardrail${errors.length > 1 ? "s" : ""} failed`);
|
||||
toast.fromError(`${errors.length} guardrail${errors.length > 1 ? "s" : ""} failed`);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from "react";
|
||||
import { Check, ChevronDown, ChevronRight, Clock, Copy } from "lucide-react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
|
||||
|
|
@ -102,9 +102,9 @@ export function GuardrailTestResults({ results, errors }: GuardrailTestResultsPr
|
|||
onClick={async () => {
|
||||
const success = await copyToClipboard(result.response_text);
|
||||
if (success) {
|
||||
NotificationsManager.success("Result copied to clipboard");
|
||||
toast.success("Result copied to clipboard");
|
||||
} else {
|
||||
NotificationsManager.fromBackend("Failed to copy result");
|
||||
toast.fromError("Failed to copy result");
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import GuardrailTable from "./guardrail_table";
|
|||
import { isAdminRole } from "@/utils/roles";
|
||||
import GuardrailInfoView from "./guardrail_info";
|
||||
import GuardrailTestPlayground from "./GuardrailTestPlayground";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Guardrail } from "@/components/guardrails/types";
|
||||
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
|
||||
import { getGuardrailLogoAndName } from "./guardrail_info_helpers";
|
||||
|
|
@ -101,11 +101,11 @@ const GuardrailsPanel: React.FC<GuardrailsPanelProps> = ({ accessToken, userRole
|
|||
setIsDeleting(true);
|
||||
try {
|
||||
await deleteGuardrailCall(accessToken, guardrailToDelete.guardrail_id);
|
||||
NotificationsManager.success(`Guardrail "${guardrailToDelete.guardrail_name}" deleted successfully`);
|
||||
toast.success(`Guardrail "${guardrailToDelete.guardrail_name}" deleted successfully`);
|
||||
await fetchGuardrails();
|
||||
} catch (error) {
|
||||
console.error("Error deleting guardrail:", error);
|
||||
NotificationsManager.fromBackend("Failed to delete guardrail");
|
||||
toast.fromError("Failed to delete guardrail");
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
setIsDeleteModalOpen(false);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import {
|
|||
updateGuardrailCall,
|
||||
type GuardrailSubmissionItem,
|
||||
} from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import TeamDropdown from "@/components/common_components/team_dropdown";
|
||||
import { useRegisterGuardrail } from "@/app/(dashboard)/hooks/guardrails/useRegisterGuardrail";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
|
|
@ -814,9 +814,9 @@ export function TeamGuardrailsTab({ accessToken }: TeamGuardrailsTabProps) {
|
|||
litellm_params: { forward_api_key: newValue },
|
||||
});
|
||||
setGuardrails((prev) => prev.map((x) => (x.id === id ? { ...x, forwardKey: newValue } : x)));
|
||||
NotificationsManager.success(newValue ? "Forward API key enabled" : "Forward API key disabled");
|
||||
toast.success(newValue ? "Forward API key enabled" : "Forward API key disabled");
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Failed to update forward API key");
|
||||
toast.fromError("Failed to update forward API key");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -840,9 +840,9 @@ export function TeamGuardrailsTab({ accessToken }: TeamGuardrailsTabProps) {
|
|||
: x,
|
||||
),
|
||||
);
|
||||
NotificationsManager.success("Static headers updated");
|
||||
toast.success("Static headers updated");
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Failed to update static headers");
|
||||
toast.fromError("Failed to update static headers");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -853,9 +853,9 @@ export function TeamGuardrailsTab({ accessToken }: TeamGuardrailsTabProps) {
|
|||
litellm_params: { extra_headers: extraHeaders },
|
||||
});
|
||||
setGuardrails((prev) => prev.map((x) => (x.id === id ? { ...x, extraHeaders } : x)));
|
||||
NotificationsManager.success("Forward client headers updated");
|
||||
toast.success("Forward client headers updated");
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Failed to update forward client headers");
|
||||
toast.fromError("Failed to update forward client headers");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -866,9 +866,9 @@ export function TeamGuardrailsTab({ accessToken }: TeamGuardrailsTabProps) {
|
|||
setConfirmAction(null);
|
||||
if (selectedId === id) setSelectedId(null);
|
||||
await fetchSubmissions();
|
||||
NotificationsManager.success("Guardrail approved");
|
||||
toast.success("Guardrail approved");
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Failed to approve guardrail");
|
||||
toast.fromError("Failed to approve guardrail");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -879,9 +879,9 @@ export function TeamGuardrailsTab({ accessToken }: TeamGuardrailsTabProps) {
|
|||
setConfirmAction(null);
|
||||
if (selectedId === id) setSelectedId(null);
|
||||
await fetchSubmissions();
|
||||
NotificationsManager.success("Guardrail rejected");
|
||||
toast.success("Guardrail rejected");
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Failed to reject guardrail");
|
||||
toast.fromError("Failed to reject guardrail");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1011,7 +1011,7 @@ export function TeamGuardrailsTab({ accessToken }: TeamGuardrailsTabProps) {
|
|||
litellm_params,
|
||||
guardrail_info: values.guardrail_info ? JSON.parse(values.guardrail_info) : undefined,
|
||||
});
|
||||
NotificationsManager.success("Guardrail submitted for review");
|
||||
toast.success("Guardrail submitted for review");
|
||||
setIsSubmitModalOpen(false);
|
||||
submitForm.resetFields();
|
||||
fetchSubmissions();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Form, Input, Modal, Select, Tag, Button } from "antd";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import {
|
||||
createGuardrailCall,
|
||||
getGuardrailProviderSpecificParams,
|
||||
|
|
@ -214,7 +214,7 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
populateGuardrailProviderMap(providerParamsResp);
|
||||
} catch (error) {
|
||||
console.error("Error fetching guardrail data:", error);
|
||||
NotificationsManager.fromBackend("Failed to load guardrail configuration");
|
||||
toast.fromError("Failed to load guardrail configuration");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -344,7 +344,7 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
// Validate configuration steps
|
||||
if (currentStep === 1) {
|
||||
if (shouldRenderPIIConfigSettings(selectedProvider) && selectedEntities.length === 0) {
|
||||
NotificationsManager.fromBackend("Please select at least one PII entity to continue");
|
||||
toast.fromError("Please select at least one PII entity to continue");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -449,7 +449,7 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
const hasContentFilterSelections =
|
||||
selectedPatterns.length > 0 || blockedWords.length > 0 || selectedContentCategories.length > 0;
|
||||
if (!hasContentFilterSelections && !hasCompetitorIntent) {
|
||||
NotificationsManager.fromBackend(
|
||||
toast.fromError(
|
||||
"Please configure at least one content filter setting (category, pattern, keyword, or competitor intent)",
|
||||
);
|
||||
setLoading(false);
|
||||
|
|
@ -505,7 +505,7 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
// For some guardrails, the config values need to be in litellm_params
|
||||
guardrailData.guardrail_info = configObj;
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend("Invalid JSON in configuration");
|
||||
toast.fromError("Invalid JSON in configuration");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
|
@ -514,13 +514,13 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
if (guardrailProvider === "llm_as_a_judge") {
|
||||
const criteria: JudgeCriterion[] = values.criteria || [];
|
||||
if (criteria.length === 0) {
|
||||
NotificationsManager.fromBackend("Add at least one evaluation criterion");
|
||||
toast.fromError("Add at least one evaluation criterion");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
const weightTotal = criteria.reduce((sum, c) => sum + (Number(c?.weight) || 0), 0);
|
||||
if (weightTotal !== 100) {
|
||||
NotificationsManager.fromBackend(`Criterion weights must sum to 100% (currently ${weightTotal}%)`);
|
||||
toast.fromError(`Criterion weights must sum to 100% (currently ${weightTotal}%)`);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
|
@ -536,7 +536,7 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
|
||||
if (guardrailProvider === "tool_permission") {
|
||||
if (toolPermissionConfig.rules.length === 0) {
|
||||
NotificationsManager.fromBackend("Add at least one tool permission rule");
|
||||
toast.fromError("Add at least one tool permission rule");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
|
@ -611,7 +611,7 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
|
||||
await createGuardrailCall(accessToken, guardrailData);
|
||||
|
||||
NotificationsManager.success("Guardrail created successfully");
|
||||
toast.success("Guardrail created successfully");
|
||||
|
||||
// Reset form and close modal
|
||||
resetForm();
|
||||
|
|
@ -619,9 +619,7 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
onClose();
|
||||
} catch (error) {
|
||||
console.error("Failed to create guardrail:", error);
|
||||
NotificationsManager.fromBackend(
|
||||
"Failed to create guardrail: " + (error instanceof Error ? error.message : String(error)),
|
||||
);
|
||||
toast.fromError("Failed to create guardrail: " + (error instanceof Error ? error.message : String(error)));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,6 @@ vi.mock("@/components/networking", () => ({
|
|||
getCategoryYaml: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: { success: vi.fn(), error: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
const PREBUILT = [
|
||||
{ name: "us_ssn", display_name: "US Social Security Number", category: "PII Patterns", description: "d" },
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useRef, useState } from "react";
|
||||
import { Plus, Upload } from "lucide-react";
|
||||
import { validateBlockedWordsFile } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { UiLoadingSpinner } from "@/components/ui/ui-loading-spinner";
|
||||
|
|
@ -119,7 +119,7 @@ const ContentFilterConfiguration: React.FC<ContentFilterConfigurationProps> = ({
|
|||
|
||||
const handleAddPrebuiltPattern = () => {
|
||||
if (!selectedPatternName) {
|
||||
NotificationsManager.error("Please select a pattern");
|
||||
toast.error("Please select a pattern");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ const ContentFilterConfiguration: React.FC<ContentFilterConfigurationProps> = ({
|
|||
|
||||
const handleAddCustomPattern = () => {
|
||||
if (!customPatternName || !customPatternRegex) {
|
||||
NotificationsManager.error("Please provide pattern name and regex");
|
||||
toast.error("Please provide pattern name and regex");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ const ContentFilterConfiguration: React.FC<ContentFilterConfigurationProps> = ({
|
|||
|
||||
const handleAddKeyword = () => {
|
||||
if (!newKeyword) {
|
||||
NotificationsManager.error("Please enter a keyword");
|
||||
toast.error("Please enter a keyword");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -188,14 +188,14 @@ const ContentFilterConfiguration: React.FC<ContentFilterConfigurationProps> = ({
|
|||
if (onFileUpload) {
|
||||
onFileUpload(content);
|
||||
}
|
||||
NotificationsManager.success(result.message || "File uploaded successfully");
|
||||
toast.success(result.message || "File uploaded successfully");
|
||||
} else {
|
||||
const errorMessage = result.error || (result.errors && result.errors.join(", ")) || "Invalid file";
|
||||
NotificationsManager.error(`Validation failed: ${errorMessage}`);
|
||||
toast.error(`Validation failed: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
NotificationsManager.error(`Failed to upload file: ${error}`);
|
||||
toast.error(`Failed to upload file: ${error}`);
|
||||
} finally {
|
||||
setUploadValidating(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,10 +10,6 @@ vi.mock("@/components/networking", () => ({
|
|||
testCustomCodeGuardrail: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: { success: vi.fn(), error: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
const mockCreate = vi.mocked(createGuardrailCall);
|
||||
const mockUpdate = vi.mocked(updateGuardrailCall);
|
||||
const mockTest = vi.mocked(testCustomCodeGuardrail);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useState, useRef, useEffect } from "react";
|
||||
import { CheckCircle2, ChevronRight, Code, ExternalLink, PlayCircle, Save, Users, XCircle } from "lucide-react";
|
||||
import { createGuardrailCall, updateGuardrailCall, testCustomCodeGuardrail } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
||||
import {
|
||||
|
|
@ -364,15 +364,15 @@ const CustomCodeModal: React.FC<CustomCodeModalProps> = ({ visible, onClose, onS
|
|||
// Save guardrail (create or update)
|
||||
const handleSave = async () => {
|
||||
if (!guardrailName.trim()) {
|
||||
NotificationsManager.fromBackend("Please enter a guardrail name");
|
||||
toast.fromError("Please enter a guardrail name");
|
||||
return;
|
||||
}
|
||||
if (!code.trim()) {
|
||||
NotificationsManager.fromBackend("Please enter custom code");
|
||||
toast.fromError("Please enter custom code");
|
||||
return;
|
||||
}
|
||||
if (!accessToken) {
|
||||
NotificationsManager.fromBackend("No access token available");
|
||||
toast.fromError("No access token available");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +400,7 @@ const CustomCodeModal: React.FC<CustomCodeModalProps> = ({ visible, onClose, onS
|
|||
}
|
||||
|
||||
await updateGuardrailCall(accessToken, editData.guardrail_id, updateData);
|
||||
NotificationsManager.success("Custom code guardrail updated successfully");
|
||||
toast.success("Custom code guardrail updated successfully");
|
||||
} else {
|
||||
// Create new guardrail
|
||||
const guardrailData = {
|
||||
|
|
@ -415,13 +415,13 @@ const CustomCodeModal: React.FC<CustomCodeModalProps> = ({ visible, onClose, onS
|
|||
};
|
||||
|
||||
await createGuardrailCall(accessToken, guardrailData);
|
||||
NotificationsManager.success("Custom code guardrail created successfully");
|
||||
toast.success("Custom code guardrail created successfully");
|
||||
}
|
||||
onSuccess();
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error("Failed to save guardrail:", error);
|
||||
NotificationsManager.fromBackend(
|
||||
toast.fromError(
|
||||
`Failed to ${isEditMode ? "update" : "create"} guardrail: ` +
|
||||
(error instanceof Error ? error.message : String(error)),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { Badge, Card, Grid, Tab, TabGroup, TabList, TabPanel, TabPanels, Text, T
|
|||
import { Button, Divider, Form, Input, Select, Tooltip } from "antd";
|
||||
import { CheckIcon, CopyIcon } from "lucide-react";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Logo } from "@/components/molecules/logo/Logo";
|
||||
import ContentFilterManager, { formatContentFilterDataForAPI } from "./content_filter/ContentFilterManager";
|
||||
import CustomCodeModal, { EditGuardrailData } from "./custom_code/CustomCodeModal";
|
||||
|
|
@ -147,7 +147,7 @@ const GuardrailInfoView: React.FC<GuardrailInfoProps> = ({ guardrailId, onClose,
|
|||
setSelectedPiiActions({});
|
||||
}
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend("Failed to load guardrail information");
|
||||
toast.fromError("Failed to load guardrail information");
|
||||
console.error("Error fetching guardrail info:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
|
@ -421,19 +421,19 @@ const GuardrailInfoView: React.FC<GuardrailInfoProps> = ({ guardrailId, onClose,
|
|||
|
||||
// Only proceed with update if there are actual changes
|
||||
if (Object.keys(updateData).length === 0) {
|
||||
NotificationsManager.info("No changes detected");
|
||||
toast.info("No changes detected");
|
||||
setIsEditing(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await updateGuardrailCall(accessToken, guardrailId, updateData);
|
||||
NotificationsManager.success("Guardrail updated successfully");
|
||||
toast.success("Guardrail updated successfully");
|
||||
setHasUnsavedContentFilterChanges(false);
|
||||
fetchGuardrailInfo();
|
||||
setIsEditing(false);
|
||||
} catch (error) {
|
||||
console.error("Error updating guardrail:", error);
|
||||
NotificationsManager.fromBackend("Failed to update guardrail");
|
||||
toast.fromError("Failed to update guardrail");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ import MCPLogoSelector from "./MCPLogoSelector";
|
|||
import EnvVarsSection from "./EnvVarsSection";
|
||||
import { isAdminRole } from "@/utils/roles";
|
||||
import { validateMCPServerUrl, validateMCPServerName } from "./utils";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { useMcpOAuthFlow } from "@/hooks/useMcpOAuthFlow";
|
||||
import { useTestMCPConnection } from "@/hooks/useTestMCPConnection";
|
||||
import mcpLogo from "../../../../../public/assets/logos/mcp_logo.png";
|
||||
|
|
@ -222,7 +222,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
// which would persist it as server-level credentials on the created server row. Mirrors the
|
||||
// edit form's onTokenReceived early return.
|
||||
setAuthorizedIdentity(getOAuthAuthorizationIdentity(form.getFieldsValue(true)));
|
||||
NotificationsManager.success(
|
||||
toast.success(
|
||||
"Token held for this browser session. Tools can now be previewed and configured; the token is not saved to LiteLLM.",
|
||||
);
|
||||
return;
|
||||
|
|
@ -255,9 +255,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
// its own credential write.
|
||||
setAuthorizedIdentity(getOAuthAuthorizationIdentity(form.getFieldsValue(true)));
|
||||
|
||||
NotificationsManager.success(
|
||||
"OAuth authorization successful! Please click 'Create MCP Server' to save the configuration.",
|
||||
);
|
||||
toast.success("OAuth authorization successful! Please click 'Create MCP Server' to save the configuration.");
|
||||
},
|
||||
onBeforeRedirect: persistCreateUiState,
|
||||
flowSource: "create",
|
||||
|
|
@ -398,7 +396,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
dcrClient: dcrClientRef.current,
|
||||
});
|
||||
if (built.kind !== "ok") {
|
||||
NotificationsManager.fromBackend(payloadErrorMessage(built));
|
||||
toast.fromError(payloadErrorMessage(built));
|
||||
return;
|
||||
}
|
||||
const payload = built.payload;
|
||||
|
|
@ -439,14 +437,13 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
}
|
||||
}
|
||||
|
||||
NotificationsManager.success(
|
||||
isAdmin
|
||||
? "MCP Server created successfully"
|
||||
: {
|
||||
message: "MCP Server submitted for admin review",
|
||||
description: "Once an admin approves it, the server will appear in your MCP Servers list.",
|
||||
},
|
||||
);
|
||||
if (isAdmin) {
|
||||
toast.success("MCP Server created successfully");
|
||||
} else {
|
||||
toast.success("MCP Server submitted for admin review", {
|
||||
description: "Once an admin approves it, the server will appear in your MCP Servers list.",
|
||||
});
|
||||
}
|
||||
form.resetFields();
|
||||
setCostConfig({});
|
||||
clearTools();
|
||||
|
|
@ -459,9 +456,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
}
|
||||
} catch (error) {
|
||||
const reason = error instanceof Error ? error.message : String(error);
|
||||
NotificationsManager.fromBackend(
|
||||
isAdmin ? `Error creating MCP Server: ${reason}` : `Error submitting MCP Server: ${reason}`,
|
||||
);
|
||||
toast.fromError(isAdmin ? `Error creating MCP Server: ${reason}` : `Error submitting MCP Server: ${reason}`);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
} from "@/components/networking";
|
||||
import { MCPServer, MCPSubmissionsSummary } from "@/components/mcp_tools/types";
|
||||
import { FIELD_GROUPS, MCP_REQUIRED_FIELD_DEFS, SETTINGS_KEY } from "./MCPStandardsSettings";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
type MCPStatus = "active" | "pending_review" | "rejected";
|
||||
|
||||
|
|
@ -496,9 +496,9 @@ export function MCPSubmissionsTab({ accessToken }: MCPSubmissionsTabProps) {
|
|||
setIsSavingRules(true);
|
||||
try {
|
||||
await updateConfigFieldSetting(accessToken, SETTINGS_KEY, requiredFields);
|
||||
NotificationsManager.success("Submission rules saved");
|
||||
toast.success("Submission rules saved");
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Failed to save submission rules");
|
||||
toast.fromError("Failed to save submission rules");
|
||||
} finally {
|
||||
setIsSavingRules(false);
|
||||
}
|
||||
|
|
@ -520,9 +520,9 @@ export function MCPSubmissionsTab({ accessToken }: MCPSubmissionsTabProps) {
|
|||
try {
|
||||
await approveMCPServer(accessToken, serverId);
|
||||
await fetchData();
|
||||
NotificationsManager.success(`MCP server "${serverName}" approved`);
|
||||
toast.success(`MCP server "${serverName}" approved`);
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Failed to approve MCP server");
|
||||
toast.fromError("Failed to approve MCP server");
|
||||
} finally {
|
||||
setConfirmAction(null);
|
||||
}
|
||||
|
|
@ -533,9 +533,9 @@ export function MCPSubmissionsTab({ accessToken }: MCPSubmissionsTabProps) {
|
|||
try {
|
||||
await rejectMCPServer(accessToken, serverId, reviewNotes);
|
||||
await fetchData();
|
||||
NotificationsManager.success(`MCP server "${serverName}" rejected`);
|
||||
toast.success(`MCP server "${serverName}" rejected`);
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Failed to reject MCP server");
|
||||
toast.fromError("Failed to reject MCP server");
|
||||
} finally {
|
||||
setConfirmAction(null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,16 +5,6 @@ import { describe, expect, it, vi } from "vitest";
|
|||
import { ToolTestPanel } from "./ToolTestPanel";
|
||||
import { InputSchema, MCPTool } from "@/components/mcp_tools/types";
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: {
|
||||
success: vi.fn(),
|
||||
fromBackend: vi.fn(),
|
||||
info: vi.fn(),
|
||||
warning: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const buildTool = (schema: InputSchema | string): MCPTool => ({
|
||||
name: "demo-tool",
|
||||
description: "demo",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { MCPTool, InputSchema, InputSchemaProperty } from "@/components/mcp_tool
|
|||
import { resolveLogoSrc } from "@/lib/assetPaths";
|
||||
import { Form, Select, Tooltip } from "antd";
|
||||
import { InfoCircleOutlined } from "@ant-design/icons";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
const isPlainObject = (value: unknown): value is Record<string, any> =>
|
||||
typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
|
|
@ -279,18 +279,18 @@ export function ToolTestPanel({
|
|||
const handleCopyResult = async () => {
|
||||
const success = await copyToClipboard(JSON.stringify(result, null, 2));
|
||||
if (success) {
|
||||
NotificationsManager.success("Result copied to clipboard");
|
||||
toast.success("Result copied to clipboard");
|
||||
} else {
|
||||
NotificationsManager.fromBackend("Failed to copy result");
|
||||
toast.fromError("Failed to copy result");
|
||||
}
|
||||
};
|
||||
|
||||
const handleCopyToolName = async () => {
|
||||
const success = await copyToClipboard(tool.name);
|
||||
if (success) {
|
||||
NotificationsManager.success("Tool name copied to clipboard");
|
||||
toast.success("Tool name copied to clipboard");
|
||||
} else {
|
||||
NotificationsManager.fromBackend("Failed to copy tool name");
|
||||
toast.fromError("Failed to copy tool name");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Modal, Form, Input, Button, Alert, Spin, Tag, Typography } from "antd";
|
|||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { MCPServer, MCPUserEnvVarsStatus } from "@/components/mcp_tools/types";
|
||||
import { getMCPUserEnvVars, storeMCPUserEnvVars } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
const { Text, Title } = Typography;
|
||||
|
||||
|
|
@ -38,12 +38,12 @@ const UserEnvVarsModal: React.FC<UserEnvVarsModalProps> = ({ server, open, acces
|
|||
const saveMutation = useMutation({
|
||||
mutationFn: (values: Record<string, string>) => storeMCPUserEnvVars(accessToken!, server!.server_id, values),
|
||||
onSuccess: (saved) => {
|
||||
NotificationsManager.success("Credentials saved");
|
||||
toast.success("Credentials saved");
|
||||
onSaved?.(saved);
|
||||
onClose();
|
||||
},
|
||||
onError: (err) => {
|
||||
NotificationsManager.fromBackend(`Failed to save env vars: ${err instanceof Error ? err.message : String(err)}`);
|
||||
toast.fromError(`Failed to save env vars: ${err instanceof Error ? err.message : String(err)}`);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import userEvent from "@testing-library/user-event";
|
|||
import MCPServerEdit, { EDIT_OAUTH_UI_STATE_KEY } from "./mcp_server_edit";
|
||||
import { setSecureItem } from "@/utils/secureStorage";
|
||||
import * as networking from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { selectAntOption } from "./testUtils";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
|
|
@ -15,13 +15,6 @@ vi.mock("@/components/networking", () => ({
|
|||
testMCPToolsListRequest: vi.fn().mockResolvedValue({ tools: [], error: null }),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: {
|
||||
success: vi.fn(),
|
||||
fromBackend: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const mockOauth: {
|
||||
tokenResponse: any;
|
||||
getTemporaryPayload: (() => Record<string, unknown> | null) | null;
|
||||
|
|
@ -1390,10 +1383,8 @@ describe("MCPServerEdit (OAuth token persistence on save)", () => {
|
|||
await waitFor(() => {
|
||||
expect(networking.storeMCPOAuthUserCredential).toHaveBeenCalled();
|
||||
});
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(
|
||||
"MCP Server updated, but failed to persist OAuth token: write failed",
|
||||
);
|
||||
expect(NotificationsManager.success).not.toHaveBeenCalledWith("MCP Server updated successfully");
|
||||
expect(toast.fromError).toHaveBeenCalledWith("MCP Server updated, but failed to persist OAuth token: write failed");
|
||||
expect(toast.success).not.toHaveBeenCalledWith("MCP Server updated successfully");
|
||||
expect(onSuccess).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ import {
|
|||
normalizeToolOverrideMap,
|
||||
TOOL_DISPLAY_NAME_PATTERN,
|
||||
} from "./utils";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { useMcpOAuthFlow } from "@/hooks/useMcpOAuthFlow";
|
||||
import { getSecureItem, setSecureItem } from "@/utils/secureStorage";
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
token_type: token.token_type,
|
||||
};
|
||||
setToken(mcpServer.server_id, browserHeldToken, userID);
|
||||
NotificationsManager.success(
|
||||
toast.success(
|
||||
"Token held for this browser session. Tools can now be loaded and configured; the token is not saved to LiteLLM.",
|
||||
);
|
||||
return;
|
||||
|
|
@ -242,9 +242,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
// Re-capture after writing credentials so the token is not invalidated by its own credential write.
|
||||
authorizedIdentityRef.current = getOAuthAuthorizationIdentity(form.getFieldsValue(true));
|
||||
|
||||
NotificationsManager.success(
|
||||
"OAuth authorization successful! Please click 'Update MCP Server' to save the credentials.",
|
||||
);
|
||||
toast.success("OAuth authorization successful! Please click 'Update MCP Server' to save the credentials.");
|
||||
},
|
||||
onBeforeRedirect: persistEditUiState,
|
||||
flowSource: "edit",
|
||||
|
|
@ -677,7 +675,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
([, displayName]) => displayName && !TOOL_DISPLAY_NAME_PATTERN.test(displayName),
|
||||
);
|
||||
if (invalidDisplayName) {
|
||||
NotificationsManager.fromBackend(
|
||||
toast.fromError(
|
||||
`Tool display name "${invalidDisplayName[1]}" is invalid. Only letters, digits, underscores, and hyphens are allowed (no spaces).`,
|
||||
);
|
||||
return;
|
||||
|
|
@ -777,11 +775,11 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
};
|
||||
|
||||
if (!stdioFields.command) {
|
||||
NotificationsManager.fromBackend("Stdio configuration must include a command");
|
||||
toast.fromError("Stdio configuration must include a command");
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Invalid JSON in stdio configuration");
|
||||
toast.fromError("Invalid JSON in stdio configuration");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -798,7 +796,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
}, {});
|
||||
}
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Invalid JSON in stdio env configuration");
|
||||
toast.fromError("Invalid JSON in stdio env configuration");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -808,7 +806,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
|
||||
const parsedCommand = rawCommand ? String(rawCommand).trim() : "";
|
||||
if (!parsedCommand) {
|
||||
NotificationsManager.fromBackend("Stdio transport requires a command");
|
||||
toast.fromError("Stdio transport requires a command");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -831,7 +829,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
try {
|
||||
tokenValidation = JSON.parse(rawTokenValidationJson);
|
||||
} catch {
|
||||
NotificationsManager.fromBackend("Invalid JSON in Token Validation Rules");
|
||||
toast.fromError("Invalid JSON in Token Validation Rules");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -982,18 +980,16 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
}
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : "";
|
||||
NotificationsManager.fromBackend(
|
||||
"MCP Server updated, but failed to persist OAuth token" + (message ? `: ${message}` : ""),
|
||||
);
|
||||
toast.fromError("MCP Server updated, but failed to persist OAuth token" + (message ? `: ${message}` : ""));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NotificationsManager.success("MCP Server updated successfully");
|
||||
toast.success("MCP Server updated successfully");
|
||||
setAppMayNotMatchUpstream(false);
|
||||
onSuccess(updated);
|
||||
} catch (error: any) {
|
||||
NotificationsManager.fromBackend("Failed to update MCP Server" + (error?.message ? `: ${error.message}` : ""));
|
||||
toast.fromError("Failed to update MCP Server" + (error?.message ? `: ${error.message}` : ""));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,14 +19,6 @@ vi.mock("@/components/networking", () => ({
|
|||
listMCPUserEnvVarStatus: vi.fn().mockResolvedValue([]),
|
||||
}));
|
||||
|
||||
// Mock NotificationsManager
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: {
|
||||
success: vi.fn(),
|
||||
fromBackend: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const createQueryClient = () =>
|
||||
new QueryClient({
|
||||
defaultOptions: {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import React, { useEffect, useState, useMemo, useCallback } from "react";
|
|||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useMCPServers } from "@/app/(dashboard)/hooks/mcpServers/useMCPServers";
|
||||
import { useMCPServerHealth } from "@/app/(dashboard)/hooks/mcpServers/useMCPServerHealth";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { deleteMCPServer } from "@/components/networking";
|
||||
import { MCPSubmissionsTab } from "./MCPSubmissionsTab";
|
||||
import { MCPToolsetsTab } from "./MCPToolsetsTab";
|
||||
|
|
@ -350,7 +350,7 @@ const MCPServers: React.FC<MCPServerProps> = ({ accessToken, userRole, userID })
|
|||
try {
|
||||
setIsDeletingServer(true);
|
||||
await deleteMCPServer(accessToken, serverIdToDelete);
|
||||
NotificationsManager.success("Deleted MCP Server successfully");
|
||||
toast.success("Deleted MCP Server successfully");
|
||||
// If the user is currently viewing the detail page of the server they
|
||||
// just deleted, return them to the All Servers list. Otherwise the
|
||||
// detail view would stay mounted, fall back to an empty stub server,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import React, { useCallback, useMemo, useState } from "react";
|
|||
|
||||
import { MemoryRow, createMemory, deleteMemory, fetchMemoryList, updateMemory } from "@/components/networking";
|
||||
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { DEBOUNCE_WAIT_MS } from "@/utils/debounceConstants";
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ export const MemoryView: React.FC<MemoryViewProps> = ({ accessToken }) => {
|
|||
// All three write endpoints share the same success/error plumbing:
|
||||
// - on success: invalidate the list query so every cached page
|
||||
// refetches from scratch (pagination + filter-aware).
|
||||
// - on error: surface the message via `MessageManager.error`.
|
||||
// - on error: surface the message via `toast.error`.
|
||||
|
||||
const invalidateList = useCallback(
|
||||
() => queryClient.invalidateQueries({ queryKey: [MEMORY_LIST_KEY] }),
|
||||
|
|
@ -74,11 +74,11 @@ export const MemoryView: React.FC<MemoryViewProps> = ({ accessToken }) => {
|
|||
return createMemory(accessToken, args);
|
||||
},
|
||||
onSuccess: (row) => {
|
||||
MessageManager.success(`Created ${row.key}`);
|
||||
toast.success(`Created ${row.key}`);
|
||||
invalidateList();
|
||||
},
|
||||
onError: (err: Error) => {
|
||||
MessageManager.error(`Save failed: ${err.message}`);
|
||||
toast.error(`Save failed: ${err.message}`);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -89,11 +89,11 @@ export const MemoryView: React.FC<MemoryViewProps> = ({ accessToken }) => {
|
|||
return updateMemory(accessToken, key, payload);
|
||||
},
|
||||
onSuccess: (row) => {
|
||||
MessageManager.success(`Updated ${row.key}`);
|
||||
toast.success(`Updated ${row.key}`);
|
||||
invalidateList();
|
||||
},
|
||||
onError: (err: Error) => {
|
||||
MessageManager.error(`Save failed: ${err.message}`);
|
||||
toast.error(`Save failed: ${err.message}`);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -103,11 +103,11 @@ export const MemoryView: React.FC<MemoryViewProps> = ({ accessToken }) => {
|
|||
return deleteMemory(accessToken, key).then(() => key);
|
||||
},
|
||||
onSuccess: (key) => {
|
||||
MessageManager.success(`Deleted ${key}`);
|
||||
toast.success(`Deleted ${key}`);
|
||||
invalidateList();
|
||||
},
|
||||
onError: (err: Error) => {
|
||||
MessageManager.error(`Delete failed: ${err.message}`);
|
||||
toast.error(`Delete failed: ${err.message}`);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ export const MemoryView: React.FC<MemoryViewProps> = ({ accessToken }) => {
|
|||
try {
|
||||
metadataPayload = JSON.parse(metadataText);
|
||||
} catch {
|
||||
MessageManager.error("Metadata must be valid JSON (or leave empty).");
|
||||
toast.error("Metadata must be valid JSON (or leave empty).");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,6 @@ vi.mock("@/components/networking", () => ({
|
|||
modelPatchUpdateCall: (...args: unknown[]) => mockModelPatchUpdateCall(...args),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: { success: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock("@/components/model_dashboard/ModelSettingsModal/ModelSettingsModal", () => ({
|
||||
default: function ModelSettingsModalMock({ isVisible }: { isVisible: boolean }) {
|
||||
return isVisible ? <div data-testid="model-settings-modal" /> : null;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
|||
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
|
||||
import ModelSettingsModal from "@/components/model_dashboard/ModelSettingsModal/ModelSettingsModal";
|
||||
import { ModelData } from "@/components/model_dashboard/types";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { modelDeleteCall, modelPatchUpdateCall } from "@/components/networking";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useDebouncedCallback } from "@tanstack/react-pacer/debouncer";
|
||||
|
|
@ -213,12 +213,12 @@ const AllModelsTab = ({
|
|||
try {
|
||||
setDeleteLoading(true);
|
||||
await modelDeleteCall(accessToken, deleteModalModelId);
|
||||
NotificationsManager.success("Model deleted successfully");
|
||||
toast.success("Model deleted successfully");
|
||||
queryClient.invalidateQueries({ queryKey: ["models", "list"] });
|
||||
refetchModels();
|
||||
} catch (error) {
|
||||
console.error("Error deleting model:", error);
|
||||
NotificationsManager.fromBackend(error);
|
||||
toast.fromError(error);
|
||||
} finally {
|
||||
setDeleteLoading(false);
|
||||
setDeleteModalModelId(null);
|
||||
|
|
@ -231,13 +231,13 @@ const AllModelsTab = ({
|
|||
try {
|
||||
setPausingModelId(modelId);
|
||||
await modelPatchUpdateCall(accessToken, { blocked }, modelId);
|
||||
NotificationsManager.success(blocked ? "Model paused" : "Model resumed");
|
||||
toast.success(blocked ? "Model paused" : "Model resumed");
|
||||
// invalidateQueries already schedules a refetch for active observers
|
||||
// on this key — no need to also call refetchModels() (would double-fetch).
|
||||
queryClient.invalidateQueries({ queryKey: ["models", "list"] });
|
||||
} catch (error) {
|
||||
console.error("Error toggling model pause state:", error);
|
||||
NotificationsManager.fromBackend(error);
|
||||
toast.fromError(error);
|
||||
} finally {
|
||||
setPausingModelId(null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@ import { ModelData } from "@/components/model_dashboard/types";
|
|||
|
||||
import { AllModelsTable } from "./AllModelsTable";
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: { success: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
const makeModel = (overrides: Partial<ModelData> = {}): ModelData =>
|
||||
({
|
||||
model_name: "gpt-4-public",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { useAutoRouters, useInvalidateAutoRouters } from "@/app/(dashboard)/hook
|
|||
import { useModelDetailRouting } from "@/app/(dashboard)/models-and-endpoints/detailNavigation";
|
||||
import AddAutoRouterTab from "@/components/add_model/add_auto_router_tab";
|
||||
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { modelDeleteCall } from "@/components/networking";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
|
|
@ -53,11 +53,11 @@ export function AutoRoutersPanel({ accessToken, userRole, userID, teams, createS
|
|||
setIsDeleting(true);
|
||||
try {
|
||||
await modelDeleteCall(accessToken, deletingRouter.id);
|
||||
NotificationsManager.success(`Deleted auto router: ${deletingRouter.name}`);
|
||||
toast.success(`Deleted auto router: ${deletingRouter.name}`);
|
||||
setDeletingRouter(null);
|
||||
await invalidateAutoRouters();
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend(`Failed to delete auto router: ${error}`);
|
||||
toast.fromError(`Failed to delete auto router: ${error}`);
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
|||
import AddModelForm from "@/components/add_model/AddModelForm";
|
||||
import { handleAddModelSubmit } from "@/components/add_model/handle_add_model_submit";
|
||||
import { Providers, getPlaceholder, getProviderModels } from "@/components/provider_info_helpers";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { useModelCostMap } from "@/app/(dashboard)/hooks/models/useModelCostMap";
|
||||
import { useCredentials } from "@/app/(dashboard)/hooks/credentials/useCredentials";
|
||||
import { useTeams } from "@/app/(dashboard)/hooks/teams/useTeams";
|
||||
|
|
@ -34,7 +34,7 @@ export default function AddModelPanel() {
|
|||
const errorMessages =
|
||||
error.errorFields?.map((field: any) => `${field.name.join(".")}: ${field.errors.join(", ")}`).join(" | ") ||
|
||||
"Unknown validation error";
|
||||
NotificationsManager.fromBackend(`Please fill in the following required fields: ${errorMessages}`);
|
||||
toast.fromError(`Please fill in the following required fields: ${errorMessages}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { getCallbacksCall } from "@/components/networking";
|
|||
import { useUpdateRetryPolicy } from "@/app/(dashboard)/hooks/routerSettings/useUpdateRetryPolicy";
|
||||
import { useModelDashboardData } from "@/app/(dashboard)/models-and-endpoints/useModelDashboardData";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
interface RetryPolicyObject {
|
||||
[key: string]: { [retryPolicyKey: string]: number } | undefined;
|
||||
|
|
@ -69,7 +69,7 @@ export default function ModelRetrySettingsPanel() {
|
|||
{ retry_policy: globalRetryPolicy, model_group_retry_policy: modelGroupRetryPolicy },
|
||||
{
|
||||
onSuccess: () => {
|
||||
NotificationsManager.success("Retry settings saved successfully");
|
||||
toast.success("Retry settings saved successfully");
|
||||
void fetchRetrySettings().then((routerSettings) => {
|
||||
if (routerSettings) {
|
||||
applyRetrySettings(routerSettings);
|
||||
|
|
@ -77,7 +77,7 @@ export default function ModelRetrySettingsPanel() {
|
|||
});
|
||||
},
|
||||
onError: () => {
|
||||
NotificationsManager.fromBackend("Failed to save retry settings");
|
||||
toast.fromError("Failed to save retry settings");
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
import { waitFor } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
import { vertexCredentialsUploadProps } from "./vertexCredentialsUpload";
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: { success: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
const makeForm = () => ({ setFieldsValue: vi.fn() });
|
||||
|
||||
describe("vertexCredentialsUploadProps", () => {
|
||||
|
|
@ -45,7 +41,7 @@ describe("vertexCredentialsUploadProps", () => {
|
|||
props.onChange?.({ file: { name: "vertex.json", status: "done" } } as never);
|
||||
props.onChange?.({ file: { name: "vertex.json", status: "error" } } as never);
|
||||
|
||||
expect(NotificationsManager.success).toHaveBeenCalledWith("vertex.json file uploaded successfully");
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith("vertex.json file upload failed.");
|
||||
expect(toast.success).toHaveBeenCalledWith("vertex.json file uploaded successfully");
|
||||
expect(toast.fromError).toHaveBeenCalledWith("vertex.json file upload failed.");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { ComponentProps } from "react";
|
||||
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import type CredentialsPanel from "@/components/model_add/CredentialsPanel";
|
||||
|
||||
interface VertexCredentialsForm {
|
||||
|
|
@ -28,9 +28,9 @@ export function vertexCredentialsUploadProps(form: VertexCredentialsForm): Uploa
|
|||
},
|
||||
onChange(info) {
|
||||
if (info.file.status === "done") {
|
||||
NotificationsManager.success(`${info.file.name} file uploaded successfully`);
|
||||
toast.success(`${info.file.name} file uploaded successfully`);
|
||||
} else if (info.file.status === "error") {
|
||||
NotificationsManager.fromBackend(`${info.file.name} file upload failed.`);
|
||||
toast.fromError(`${info.file.name} file upload failed.`);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
|||
import { parseAsString, useQueryState } from "nuqs";
|
||||
import React, { useState } from "react";
|
||||
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { organizationDeleteCall } from "@/components/networking";
|
||||
import { OrgCreateDialog } from "@/components/organization/org-create/OrgCreateDialog";
|
||||
import OrganizationInfoView from "@/components/organization/organization_view";
|
||||
|
|
@ -61,7 +61,7 @@ const OrganizationsPanel: React.FC<OrganizationsPanelProps> = ({ userRole, acces
|
|||
try {
|
||||
setIsDeleting(true);
|
||||
await organizationDeleteCall(accessToken, orgToDelete);
|
||||
NotificationsManager.success("Organization deleted successfully");
|
||||
toast.success("Organization deleted successfully");
|
||||
|
||||
setIsDeleteModalOpen(false);
|
||||
setOrgToDelete(null);
|
||||
|
|
|
|||
|
|
@ -34,10 +34,6 @@ vi.mock("@/components/CodeBlock", () => ({
|
|||
default: ({ code }: { code: string }) => <pre data-testid="code-block">{code}</pre>,
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: { success: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
const StatefulPanel = ({ label }: { label: string }) => {
|
||||
const [draft, setDraft] = useState("");
|
||||
return <input aria-label={label} value={draft} onChange={(event) => setDraft(event.target.value)} />;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { UiLoadingSpinner } from "@/components/ui/ui-loading-spinner";
|
|||
import { MultiSelect } from "@/components/shared/MultiSelect";
|
||||
import { useVisitedTabs } from "@/hooks/useVisitedTabs";
|
||||
import CodeBlock from "@/components/CodeBlock";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import {
|
||||
keyCreateCall,
|
||||
modelCreateCall,
|
||||
|
|
@ -240,7 +240,7 @@ export default function AgentBuilderView({
|
|||
return list;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
NotificationsManager.fromBackend("Failed to load agents");
|
||||
toast.fromError("Failed to load agents");
|
||||
return [];
|
||||
} finally {
|
||||
setLoadingAgents(false);
|
||||
|
|
@ -333,7 +333,7 @@ export default function AgentBuilderView({
|
|||
|
||||
const handleSaveAgent = async () => {
|
||||
if (!accessToken || !draftName?.trim() || !draftUnderlyingModel) {
|
||||
NotificationsManager.fromBackend("Name and underlying model are required");
|
||||
toast.fromError("Name and underlying model are required");
|
||||
return;
|
||||
}
|
||||
setSaving(true);
|
||||
|
|
@ -360,7 +360,7 @@ export default function AgentBuilderView({
|
|||
setSelectedId(created ? getAgentSelectionKey(created) : list[0] ? getAgentSelectionKey(list[0]) : null);
|
||||
goToTab("chat");
|
||||
} catch (e) {
|
||||
NotificationsManager.fromBackend("Failed to save agent");
|
||||
toast.fromError("Failed to save agent");
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
|
|
@ -368,7 +368,7 @@ export default function AgentBuilderView({
|
|||
|
||||
const handleUpdateAgent = async () => {
|
||||
if (!accessToken || !selectedAgent || !selectedAgentModelId || !draftName?.trim() || !draftUnderlyingModel) {
|
||||
NotificationsManager.fromBackend("Name and underlying model are required");
|
||||
toast.fromError("Name and underlying model are required");
|
||||
return;
|
||||
}
|
||||
setSaving(true);
|
||||
|
|
@ -388,13 +388,13 @@ export default function AgentBuilderView({
|
|||
},
|
||||
selectedAgentModelId,
|
||||
);
|
||||
NotificationsManager.success("Agent updated successfully");
|
||||
toast.success("Agent updated successfully");
|
||||
const list = await loadAgents();
|
||||
const stillSelected = list.find((a) => getAgentModelId(a) === selectedAgentModelId);
|
||||
const target = stillSelected ?? list[0];
|
||||
setSelectedId(target ? getAgentSelectionKey(target) : null);
|
||||
} catch (e) {
|
||||
NotificationsManager.fromBackend("Failed to update agent");
|
||||
toast.fromError("Failed to update agent");
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
|
|
@ -412,12 +412,12 @@ export default function AgentBuilderView({
|
|||
const keyValue = response?.key ?? null;
|
||||
if (keyValue) {
|
||||
setCreatedKeyValue(keyValue);
|
||||
NotificationsManager.success("Virtual key created. Use it in the curl example below.");
|
||||
toast.success("Virtual key created. Use it in the curl example below.");
|
||||
} else {
|
||||
NotificationsManager.fromBackend("Key created but value not returned");
|
||||
toast.fromError("Key created but value not returned");
|
||||
}
|
||||
} catch (e) {
|
||||
NotificationsManager.fromBackend("Failed to create key for agent");
|
||||
toast.fromError("Failed to create key for agent");
|
||||
} finally {
|
||||
setCreatingKey(false);
|
||||
}
|
||||
|
|
@ -433,12 +433,12 @@ export default function AgentBuilderView({
|
|||
setDeleting(true);
|
||||
try {
|
||||
await modelDeleteCall(accessToken, selectedAgentModelId);
|
||||
NotificationsManager.success("Agent deleted");
|
||||
toast.success("Agent deleted");
|
||||
const list = await loadAgents();
|
||||
const remaining = list.filter((a) => getAgentModelId(a) !== selectedAgentModelId);
|
||||
setSelectedId(remaining.length > 0 ? getAgentSelectionKey(remaining[0]) : null);
|
||||
} catch (e) {
|
||||
NotificationsManager.fromBackend("Failed to delete agent");
|
||||
toast.fromError("Failed to delete agent");
|
||||
} finally {
|
||||
setDeleting(false);
|
||||
setConfirmingDelete(false);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useId, useRef } from "react";
|
||||
import { Paperclip } from "lucide-react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { CHAT_ATTACHMENT_ACCEPT, validateChatAttachment } from "./uploadValidation";
|
||||
|
|
@ -29,7 +29,7 @@ const ChatImageUpload: React.FC<ChatImageUploadProps> = ({ chatUploadedImage, on
|
|||
}
|
||||
const result = validateChatAttachment(file);
|
||||
if (!result.ok) {
|
||||
NotificationsManager.error(result.error);
|
||||
toast.error(result.error);
|
||||
return;
|
||||
}
|
||||
onImageUpload(file);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import PolicySelector from "@/components/policies/PolicySelector";
|
|||
import MCPToolArgumentsForm, { MCPToolArgumentsFormRef } from "@/components/mcp_tools/MCPToolArgumentsForm";
|
||||
import { MCPServer } from "@/components/mcp_tools/types";
|
||||
import { ByokCredentialModal } from "@/components/mcp_tools/ByokCredentialModal";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { callMCPTool, fetchMCPServers, fetchMCPToolsets, listMCPTools } from "@/components/networking";
|
||||
import { MCPTool, MCPToolset } from "@/components/mcp_tools/types";
|
||||
import TagSelector from "@/components/tag_management/TagSelector";
|
||||
|
|
@ -512,7 +512,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
abortControllerRef.current.abort();
|
||||
abortControllerRef.current = null;
|
||||
setIsLoading(false);
|
||||
NotificationsManager.info("Request cancelled");
|
||||
toast.info("Request cancelled");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -528,7 +528,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
for (const file of files) {
|
||||
const result = validateImageEditFile(file, nextCount);
|
||||
if (!result.ok) {
|
||||
NotificationsManager.error(result.error);
|
||||
toast.error(result.error);
|
||||
continue;
|
||||
}
|
||||
accepted.push(file);
|
||||
|
|
@ -565,7 +565,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
const handleResponsesImageUpload = (file: File): void => {
|
||||
const result = validateChatAttachment(file);
|
||||
if (!result.ok) {
|
||||
NotificationsManager.error(result.error);
|
||||
toast.error(result.error);
|
||||
return;
|
||||
}
|
||||
setResponsesUploadedImage(file);
|
||||
|
|
@ -583,7 +583,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
const handleChatImageUpload = (file: File): void => {
|
||||
const result = validateChatAttachment(file);
|
||||
if (!result.ok) {
|
||||
NotificationsManager.error(result.error);
|
||||
toast.error(result.error);
|
||||
return;
|
||||
}
|
||||
setChatUploadedImage(file);
|
||||
|
|
@ -601,7 +601,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
const handleAudioUpload = (file: File): void => {
|
||||
const result = validateAudioFile(file);
|
||||
if (!result.ok) {
|
||||
NotificationsManager.error(result.error);
|
||||
toast.error(result.error);
|
||||
return;
|
||||
}
|
||||
setUploadedAudio(file);
|
||||
|
|
@ -706,19 +706,19 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
|
||||
// For image edits, require both image and prompt
|
||||
if (endpointType === EndpointType.IMAGE_EDITS && uploadedImages.length === 0) {
|
||||
NotificationsManager.fromBackend("Please upload at least one image for editing");
|
||||
toast.fromError("Please upload at least one image for editing");
|
||||
return;
|
||||
}
|
||||
|
||||
// For audio transcriptions, require audio file
|
||||
if (endpointType === EndpointType.TRANSCRIPTION && !uploadedAudio) {
|
||||
NotificationsManager.fromBackend("Please upload an audio file for transcription");
|
||||
toast.fromError("Please upload an audio file for transcription");
|
||||
return;
|
||||
}
|
||||
|
||||
// For A2A agents, require agent selection
|
||||
if (endpointType === EndpointType.A2A_AGENTS && !selectedAgent) {
|
||||
NotificationsManager.fromBackend("Please select an agent to send a message");
|
||||
toast.fromError("Please select an agent to send a message");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -728,11 +728,11 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
const rawSelected =
|
||||
selectedMCPServers.length === 1 && selectedMCPServers[0] !== "__all__" ? selectedMCPServers[0] : null;
|
||||
if (!rawSelected) {
|
||||
NotificationsManager.fromBackend("Please select an MCP server to test");
|
||||
toast.fromError("Please select an MCP server to test");
|
||||
return;
|
||||
}
|
||||
if (!selectedMCPDirectTool) {
|
||||
NotificationsManager.fromBackend("Please select an MCP tool to call");
|
||||
toast.fromError("Please select an MCP tool to call");
|
||||
return;
|
||||
}
|
||||
// For toolsets, find the tool in the servers that back this toolset
|
||||
|
|
@ -750,13 +750,13 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
}
|
||||
const mcpTool = searchPool.find((t: any) => t.name === selectedMCPDirectTool);
|
||||
if (!mcpTool) {
|
||||
NotificationsManager.fromBackend("Please wait for tool schema to load");
|
||||
toast.fromError("Please wait for tool schema to load");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mcpToolArguments = (await mcpToolArgsFormRef.current?.getSubmitValues()) ?? {};
|
||||
} catch (err) {
|
||||
NotificationsManager.fromBackend(err instanceof Error ? err.message : "Please fill in all required parameters");
|
||||
toast.fromError(err instanceof Error ? err.message : "Please fill in all required parameters");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -775,7 +775,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
];
|
||||
|
||||
if (modelRequiredEndpoints.includes(endpointType as EndpointType) && !selectedModel) {
|
||||
NotificationsManager.fromBackend("Please select a model before sending a request");
|
||||
toast.fromError("Please select a model before sending a request");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -786,7 +786,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
const effectiveApiKey = simplified ? accessToken : apiKeySource === "session" ? accessToken : apiKey;
|
||||
|
||||
if (!effectiveApiKey) {
|
||||
NotificationsManager.fromBackend("Please provide a Virtual Key or select Current UI Session");
|
||||
toast.fromError("Please provide a Virtual Key or select Current UI Session");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -802,7 +802,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
try {
|
||||
newUserMessage = await createMultimodalMessage(inputMessage, responsesUploadedImage);
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend("Failed to process image. Please try again.");
|
||||
toast.fromError("Failed to process image. Please try again.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -811,7 +811,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
try {
|
||||
newUserMessage = await createChatMultimodalMessage(inputMessage, chatUploadedImage);
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend("Failed to process image. Please try again.");
|
||||
toast.fromError("Failed to process image. Please try again.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1139,7 +1139,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
handleRemoveResponsesImage();
|
||||
handleRemoveChatImage();
|
||||
handleRemoveAudio();
|
||||
NotificationsManager.success("Chat history cleared.");
|
||||
toast.success("Chat history cleared.");
|
||||
};
|
||||
|
||||
const onModelChange = (value: string) => {
|
||||
|
|
@ -2028,7 +2028,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
onToggle={() => {
|
||||
codeInterpreter.toggle();
|
||||
if (!codeInterpreter.enabled) {
|
||||
NotificationsManager.success("Code Interpreter enabled!");
|
||||
toast.success("Code Interpreter enabled!");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
|
@ -2098,8 +2098,8 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
size="sm"
|
||||
onClick={() => {
|
||||
void navigator.clipboard.writeText(generatedCode).then(
|
||||
() => NotificationsManager.success("Copied to clipboard!"),
|
||||
() => NotificationsManager.error("Unable to copy to clipboard"),
|
||||
() => toast.success("Copied to clipboard!"),
|
||||
() => toast.error("Unable to copy to clipboard"),
|
||||
);
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Code, Info, TriangleAlert } from "lucide-react";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
|
|
@ -39,7 +39,7 @@ const CodeInterpreterTool: React.FC<CodeInterpreterToolProps> = ({
|
|||
|
||||
const handleToggle = (checked: boolean) => {
|
||||
if (checked && !isOpenAI) {
|
||||
MessageManager.warning("Code Interpreter is only available for OpenAI models");
|
||||
toast.warning("Code Interpreter is only available for OpenAI models");
|
||||
return;
|
||||
}
|
||||
onEnabledChange(checked);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useId, useRef } from "react";
|
||||
import { Paperclip } from "lucide-react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { CHAT_ATTACHMENT_ACCEPT, validateChatAttachment } from "./uploadValidation";
|
||||
|
|
@ -33,7 +33,7 @@ const ResponsesImageUpload: React.FC<ResponsesImageUploadProps> = ({
|
|||
}
|
||||
const result = validateChatAttachment(file);
|
||||
if (!result.ok) {
|
||||
NotificationsManager.error(result.error);
|
||||
toast.error(result.error);
|
||||
return;
|
||||
}
|
||||
onImageUpload(file);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { Copy, Info } from "lucide-react";
|
||||
import { EndpointType } from "@/components/chat_ui/mode_endpoint_mapping";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
|
|
@ -27,9 +27,9 @@ const SessionManagement: React.FC<SessionManagementProps> = ({
|
|||
if (responsesSessionId) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(responsesSessionId);
|
||||
NotificationsManager.success("Response ID copied to clipboard!");
|
||||
toast.success("Response ID copied to clipboard!");
|
||||
} catch {
|
||||
NotificationsManager.error("Unable to copy response ID");
|
||||
toast.error("Unable to copy response ID");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { DEBOUNCE_WAIT_MS } from "@/utils/debounceConstants";
|
||||
import { Eraser, FileText, Plus, Trash2 } from "lucide-react";
|
||||
import { useDebouncedValue } from "@tanstack/react-pacer/debouncer";
|
||||
|
|
@ -482,7 +482,7 @@ export default function CompareUI({ accessToken, disabledPersonalKeyCreation }:
|
|||
return;
|
||||
}
|
||||
if (!effectiveApiKey) {
|
||||
NotificationsManager.fromBackend("Please provide a Virtual Key or select Current UI Session");
|
||||
toast.fromError("Please provide a Virtual Key or select Current UI Session");
|
||||
return;
|
||||
}
|
||||
const targetComparisons = comparisons;
|
||||
|
|
@ -491,7 +491,7 @@ export default function CompareUI({ accessToken, disabledPersonalKeyCreation }:
|
|||
}
|
||||
// Validate selection based on endpoint type
|
||||
if (targetComparisons.some((comparison) => !hasValidSelection(comparison, selectedEndpoint))) {
|
||||
NotificationsManager.fromBackend(endpointConfig.validationMessage);
|
||||
toast.fromError(endpointConfig.validationMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -628,7 +628,7 @@ export default function CompareUI({ accessToken, disabledPersonalKeyCreation }:
|
|||
.catch((error) => {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
console.error("CompareUI: failed to fetch response", error);
|
||||
NotificationsManager.fromBackend(errorMessage);
|
||||
toast.fromError(errorMessage);
|
||||
setComparisons((prev) =>
|
||||
prev.map((comparison) => {
|
||||
if (comparison.id !== prepared.id) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { TokenUsage } from "@/components/chat_ui/ResponseMetrics";
|
|||
import { buildMcpToolBlocks } from "@/components/llm_calls/mcp_tool_blocks";
|
||||
import { MCPServer, MCPToolset } from "@/components/mcp_tools/types";
|
||||
import { getProxyBaseUrl } from "@/components/networking";
|
||||
import NotificationManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { extractPromptCacheTokens } from "@/utils/promptCacheUsage";
|
||||
|
||||
export async function makeAnthropicMessagesRequest(
|
||||
|
|
@ -118,9 +118,7 @@ export async function makeAnthropicMessagesRequest(
|
|||
} catch (error) {
|
||||
if (signal?.aborted) {
|
||||
} else {
|
||||
NotificationManager.fromBackend(
|
||||
`Error occurred while generating model response. Please try again. Error: ${error}`,
|
||||
);
|
||||
toast.fromError(`Error occurred while generating model response. Please try again. Error: ${error}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import openai from "openai";
|
||||
import { getProxyBaseUrl } from "@/components/networking";
|
||||
import NotificationManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import type { OpenAIVoice } from "../components/chat_ui/chatConstants";
|
||||
|
||||
export async function makeOpenAIAudioSpeechRequest(
|
||||
|
|
@ -49,7 +49,7 @@ export async function makeOpenAIAudioSpeechRequest(
|
|||
} catch (error) {
|
||||
if (signal?.aborted) {
|
||||
} else {
|
||||
NotificationManager.fromBackend(`Error occurred while generating speech. Please try again. Error: ${error}`);
|
||||
toast.fromError(`Error occurred while generating speech. Please try again. Error: ${error}`);
|
||||
}
|
||||
throw error; // Re-throw to allow the caller to handle the error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import openai from "openai";
|
||||
import { getProxyBaseUrl } from "@/components/networking";
|
||||
import NotificationManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
export async function makeOpenAIAudioTranscriptionRequest(
|
||||
audioFile: File,
|
||||
|
|
@ -45,7 +45,7 @@ export async function makeOpenAIAudioTranscriptionRequest(
|
|||
// The response is a transcription object with a text field
|
||||
if (response && response.text) {
|
||||
updateUI(response.text, selectedModel);
|
||||
NotificationManager.success(`Audio transcribed successfully`);
|
||||
toast.success(`Audio transcribed successfully`);
|
||||
} else {
|
||||
throw new Error("No transcription text in response");
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ export async function makeOpenAIAudioTranscriptionRequest(
|
|||
errorMessage = error.message;
|
||||
}
|
||||
|
||||
NotificationManager.fromBackend(`Audio transcription failed: ${errorMessage}`);
|
||||
toast.fromError(`Audio transcription failed: ${errorMessage}`);
|
||||
}
|
||||
throw error; // Re-throw to allow the caller to handle the error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import NotificationManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { getProxyBaseUrl, getGlobalLitellmHeaderName } from "@/components/networking";
|
||||
|
||||
export async function makeOpenAIEmbeddingsRequest(
|
||||
|
|
@ -57,9 +57,7 @@ export async function makeOpenAIEmbeddingsRequest(
|
|||
|
||||
updateEmbeddingsUI(JSON.stringify(embedding), responseData?.model ?? selectedModel);
|
||||
} catch (error: unknown) {
|
||||
NotificationManager.fromBackend(
|
||||
`Error occurred while making embeddings request. Please try again. Error: ${error}`,
|
||||
);
|
||||
toast.fromError(`Error occurred while making embeddings request. Please try again. Error: ${error}`);
|
||||
|
||||
throw error; // Re-throw to allow the caller to handle the error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import openai from "openai";
|
||||
import { getProxyBaseUrl } from "@/components/networking";
|
||||
import NotificationManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
export async function makeOpenAIImageEditsRequest(
|
||||
imageFiles: File | File[],
|
||||
|
|
@ -63,7 +63,7 @@ export async function makeOpenAIImageEditsRequest(
|
|||
}
|
||||
|
||||
if (results.length > 1) {
|
||||
NotificationManager.success(`Successfully processed ${results.length} images`);
|
||||
toast.success(`Successfully processed ${results.length} images`);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("Error making image edit request:", error);
|
||||
|
|
@ -78,7 +78,7 @@ export async function makeOpenAIImageEditsRequest(
|
|||
errorMessage = error.message;
|
||||
}
|
||||
|
||||
NotificationManager.fromBackend(`Image edit failed: ${errorMessage}`);
|
||||
toast.fromError(`Image edit failed: ${errorMessage}`);
|
||||
}
|
||||
throw error; // Re-throw to allow the caller to handle the error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import openai from "openai";
|
||||
import { getProxyBaseUrl } from "@/components/networking";
|
||||
import NotificationManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
export async function makeOpenAIImageGenerationRequest(
|
||||
prompt: string,
|
||||
|
|
@ -51,7 +51,7 @@ export async function makeOpenAIImageGenerationRequest(
|
|||
} catch (error) {
|
||||
if (signal?.aborted) {
|
||||
} else {
|
||||
NotificationManager.fromBackend(`Error occurred while generating image. Please try again. Error: ${error}`);
|
||||
toast.fromError(`Error occurred while generating image. Please try again. Error: ${error}`);
|
||||
}
|
||||
throw error; // Re-throw to allow the caller to handle the error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import NotificationManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { getGlobalLitellmHeaderName, getProxyBaseUrl } from "@/components/networking";
|
||||
|
||||
export async function makeInteractionsRequest(
|
||||
|
|
@ -115,7 +115,7 @@ export async function makeInteractionsRequest(
|
|||
if (signal?.aborted) {
|
||||
throw error;
|
||||
}
|
||||
NotificationManager.fromBackend(`Error occurred while making Interactions API request. Error: ${error}`);
|
||||
toast.fromError(`Error occurred while making Interactions API request. Error: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,6 @@ import { Policy } from "@/components/policies/types";
|
|||
|
||||
vi.mock("@/components/networking");
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: { success: vi.fn(), fromBackend: vi.fn(), error: vi.fn(), info: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock("./impact_preview_alert", () => ({
|
||||
default: ({ impactResult }: { impactResult: any }) =>
|
||||
React.createElement("div", { "data-testid": "impact-preview" }, `${impactResult.affected_keys_count} keys`),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Modal, Form, Select, Radio, Divider, Typography } from "antd";
|
|||
import { Button } from "@tremor/react";
|
||||
import { Policy } from "@/components/policies/types";
|
||||
import { teamListCall, keyListCall, modelAvailableCall, estimateAttachmentImpactCall } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
import { buildAttachmentData } from "./build_attachment_data";
|
||||
import { getInvalidTeamEntries } from "./scope_validation";
|
||||
|
|
@ -162,11 +162,11 @@ const AddAttachmentForm: React.FC<AddAttachmentFormProps> = ({
|
|||
const failed = results.filter((r) => r.status === "rejected") as PromiseRejectedResult[];
|
||||
|
||||
if (successCount > 0 && failed.length === 0) {
|
||||
NotificationsManager.success(
|
||||
toast.success(
|
||||
successCount === 1 ? "Attachment created successfully" : `${successCount} attachments created successfully`,
|
||||
);
|
||||
} else if (successCount > 0 && failed.length > 0) {
|
||||
NotificationsManager.fromBackend(`${successCount} attachments created, ${failed.length} failed`);
|
||||
toast.fromError(`${successCount} attachments created, ${failed.length} failed`);
|
||||
} else {
|
||||
throw new Error(failed[0]?.reason instanceof Error ? failed[0].reason.message : "Failed to create attachments");
|
||||
}
|
||||
|
|
@ -176,9 +176,7 @@ const AddAttachmentForm: React.FC<AddAttachmentFormProps> = ({
|
|||
onClose();
|
||||
} catch (error) {
|
||||
console.error("Failed to create attachment:", error);
|
||||
NotificationsManager.fromBackend(
|
||||
"Failed to create attachment: " + (error instanceof Error ? error.message : String(error)),
|
||||
);
|
||||
toast.fromError("Failed to create attachment: " + (error instanceof Error ? error.message : String(error)));
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Button, TextInput, Textarea } from "@tremor/react";
|
|||
import { Policy, PolicyCreateRequest, PolicyUpdateRequest } from "@/components/policies/types";
|
||||
import { Guardrail } from "@/components/guardrails/types";
|
||||
import { getResolvedGuardrails, modelAvailableCall } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
|
@ -322,10 +322,10 @@ const AddPolicyForm: React.FC<AddPolicyFormProps> = ({
|
|||
|
||||
if (isEditing && editingPolicy) {
|
||||
await updatePolicy(accessToken, editingPolicy.policy_id, data as PolicyUpdateRequest);
|
||||
NotificationsManager.success("Policy updated successfully");
|
||||
toast.success("Policy updated successfully");
|
||||
} else {
|
||||
await createPolicy(accessToken, data as PolicyCreateRequest);
|
||||
NotificationsManager.success("Policy created successfully");
|
||||
toast.success("Policy created successfully");
|
||||
}
|
||||
|
||||
resetForm();
|
||||
|
|
@ -333,9 +333,7 @@ const AddPolicyForm: React.FC<AddPolicyFormProps> = ({
|
|||
onClose();
|
||||
} catch (error) {
|
||||
console.error("Failed to save policy:", error);
|
||||
NotificationsManager.fromBackend(
|
||||
"Failed to save policy: " + (error instanceof Error ? error.message : String(error)),
|
||||
);
|
||||
toast.fromError("Failed to save policy: " + (error instanceof Error ? error.message : String(error)));
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Alert, AlertDescription, AlertTitle, AlertAction } from "@/components/s
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Info, TriangleAlert, X } from "lucide-react";
|
||||
import { isAdminRole } from "@/utils/roles";
|
||||
import PolicyTable from "./PolicyTable";
|
||||
|
|
@ -126,7 +126,7 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({ accessToken, userRole })
|
|||
setPoliciesList(response.policies || []);
|
||||
} catch (error) {
|
||||
console.error("Error fetching policies:", error);
|
||||
MessageManager.error("Failed to fetch policies");
|
||||
toast.error("Failed to fetch policies");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
@ -141,7 +141,7 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({ accessToken, userRole })
|
|||
setAttachmentsList(response.attachments || []);
|
||||
} catch (error) {
|
||||
console.error("Error fetching attachments:", error);
|
||||
MessageManager.error("Failed to fetch attachments");
|
||||
toast.error("Failed to fetch attachments");
|
||||
} finally {
|
||||
setIsAttachmentsLoading(false);
|
||||
}
|
||||
|
|
@ -194,11 +194,11 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({ accessToken, userRole })
|
|||
setIsDeleting(true);
|
||||
try {
|
||||
await deletePolicyCall(accessToken, policyToDelete.policy_id);
|
||||
MessageManager.success(`Policy "${policyToDelete.policy_name}" deleted successfully`);
|
||||
toast.success(`Policy "${policyToDelete.policy_name}" deleted successfully`);
|
||||
await fetchPolicies();
|
||||
} catch (error) {
|
||||
console.error("Error deleting policy:", error);
|
||||
MessageManager.error("Failed to delete policy");
|
||||
toast.error("Failed to delete policy");
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
setIsDeleteModalOpen(false);
|
||||
|
|
@ -243,7 +243,7 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({ accessToken, userRole })
|
|||
|
||||
const handleUseTemplate = async (template: any) => {
|
||||
if (!accessToken) {
|
||||
MessageManager.error("Authentication required");
|
||||
toast.error("Authentication required");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -271,7 +271,7 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({ accessToken, userRole })
|
|||
setIsGuardrailSelectionModalOpen(true);
|
||||
} catch (error) {
|
||||
console.error("Error fetching guardrails:", error);
|
||||
MessageManager.error("Failed to load guardrails. Please try again.");
|
||||
toast.error("Failed to load guardrails. Please try again.");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -321,7 +321,7 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({ accessToken, userRole })
|
|||
await proceedWithTemplate(enrichedTemplate);
|
||||
} catch (error) {
|
||||
console.error("Error enriching template:", error);
|
||||
MessageManager.error("Failed to configure template. Please try again.");
|
||||
toast.error("Failed to configure template. Please try again.");
|
||||
setIsEnrichingTemplate(false);
|
||||
}
|
||||
};
|
||||
|
|
@ -367,15 +367,15 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({ accessToken, userRole })
|
|||
|
||||
// Show success message
|
||||
if (createdGuardrails.length > 0) {
|
||||
MessageManager.success(
|
||||
toast.success(
|
||||
`Created ${createdGuardrails.length} guardrail${createdGuardrails.length > 1 ? "s" : ""}! Complete the policy form to save.`,
|
||||
);
|
||||
} else {
|
||||
MessageManager.success("Template ready! Complete the policy form to save.");
|
||||
toast.success("Template ready! Complete the policy form to save.");
|
||||
}
|
||||
|
||||
if (failedGuardrails.length > 0) {
|
||||
MessageManager.warning(
|
||||
toast.warning(
|
||||
`Failed to create ${failedGuardrails.length} guardrail(s): ${failedGuardrails.join(", ")}. You may need to create them manually.`,
|
||||
);
|
||||
}
|
||||
|
|
@ -395,7 +395,7 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({ accessToken, userRole })
|
|||
setTemplateQueue([]);
|
||||
setTemplateQueueProgress(null);
|
||||
console.error("Error creating guardrails:", error);
|
||||
MessageManager.error("Failed to create guardrails. Please try again.");
|
||||
toast.error("Failed to create guardrails. Please try again.");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState } from "react";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
|
|
@ -21,7 +21,6 @@ import {
|
|||
createPolicyVersion,
|
||||
updatePolicyVersionStatus,
|
||||
} from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { getComplianceDatasetPrompts, getFrameworks } from "@/data/compliancePrompts";
|
||||
import type { CompliancePrompt } from "@/data/compliancePrompts";
|
||||
|
||||
|
|
@ -1412,14 +1411,12 @@ export const FlowBuilderPage: React.FC<FlowBuilderPageProps> = ({
|
|||
setIsCreatingVersion(true);
|
||||
try {
|
||||
const newPolicy = await createPolicyVersion(accessToken, editingPolicy.policy_name);
|
||||
NotificationsManager.success("New draft version created");
|
||||
toast.success("New draft version created");
|
||||
onVersionCreated?.(newPolicy);
|
||||
const list = await listPolicyVersions(accessToken, editingPolicy.policy_name);
|
||||
setVersions(list.versions ?? []);
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend(
|
||||
"Failed to create version: " + (error instanceof Error ? error.message : String(error)),
|
||||
);
|
||||
toast.fromError("Failed to create version: " + (error instanceof Error ? error.message : String(error)));
|
||||
} finally {
|
||||
setIsCreatingVersion(false);
|
||||
}
|
||||
|
|
@ -1434,16 +1431,14 @@ export const FlowBuilderPage: React.FC<FlowBuilderPageProps> = ({
|
|||
setIsUpdatingStatus(true);
|
||||
try {
|
||||
const updated = await updatePolicyVersionStatus(accessToken, editingPolicy.policy_id, "published");
|
||||
NotificationsManager.success(
|
||||
toast.success(
|
||||
"Version published. You can test it in the Playground by selecting this version in the Policies dropdown.",
|
||||
);
|
||||
const list = await listPolicyVersions(accessToken, editingPolicy.policy_name ?? "");
|
||||
setVersions(list.versions ?? []);
|
||||
onVersionStatusUpdated?.(updated);
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend(
|
||||
"Failed to publish: " + (error instanceof Error ? error.message : String(error)),
|
||||
);
|
||||
toast.fromError("Failed to publish: " + (error instanceof Error ? error.message : String(error)));
|
||||
} finally {
|
||||
setIsUpdatingStatus(false);
|
||||
}
|
||||
|
|
@ -1454,14 +1449,12 @@ export const FlowBuilderPage: React.FC<FlowBuilderPageProps> = ({
|
|||
setIsUpdatingStatus(true);
|
||||
try {
|
||||
const updated = await updatePolicyVersionStatus(accessToken, editingPolicy.policy_id, "production");
|
||||
NotificationsManager.success("Version promoted to production");
|
||||
toast.success("Version promoted to production");
|
||||
const list = await listPolicyVersions(accessToken, editingPolicy.policy_name ?? "");
|
||||
setVersions(list.versions ?? []);
|
||||
onVersionStatusUpdated?.(updated);
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend(
|
||||
"Failed to promote to production: " + (error instanceof Error ? error.message : String(error)),
|
||||
);
|
||||
toast.fromError("Failed to promote to production: " + (error instanceof Error ? error.message : String(error)));
|
||||
} finally {
|
||||
setIsUpdatingStatus(false);
|
||||
}
|
||||
|
|
@ -1469,17 +1462,17 @@ export const FlowBuilderPage: React.FC<FlowBuilderPageProps> = ({
|
|||
|
||||
const handleSave = async () => {
|
||||
if (!policyName.trim()) {
|
||||
MessageManager.error("Please enter a policy name");
|
||||
toast.error("Please enter a policy name");
|
||||
return;
|
||||
}
|
||||
if (!accessToken) {
|
||||
MessageManager.error("No access token available");
|
||||
toast.error("No access token available");
|
||||
return;
|
||||
}
|
||||
|
||||
const emptySteps = pipeline.steps.filter((s) => !s.guardrail);
|
||||
if (emptySteps.length > 0) {
|
||||
MessageManager.error("Please select a guardrail for all steps");
|
||||
toast.error("Please select a guardrail for all steps");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1497,19 +1490,17 @@ export const FlowBuilderPage: React.FC<FlowBuilderPageProps> = ({
|
|||
|
||||
if (isEditing && editingPolicy) {
|
||||
await updatePolicy(accessToken, editingPolicy.policy_id, data as PolicyUpdateRequest);
|
||||
NotificationsManager.success("Policy updated successfully");
|
||||
toast.success("Policy updated successfully");
|
||||
onSuccess();
|
||||
} else {
|
||||
await createPolicy(accessToken, data as PolicyCreateRequest);
|
||||
NotificationsManager.success("Policy created successfully");
|
||||
toast.success("Policy created successfully");
|
||||
onSuccess();
|
||||
onBack();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to save policy:", error);
|
||||
NotificationsManager.fromBackend(
|
||||
"Failed to save policy: " + (error instanceof Error ? error.message : String(error)),
|
||||
);
|
||||
toast.fromError("Failed to save policy: " + (error instanceof Error ? error.message : String(error)));
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button";
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { ShieldCheck, ShieldAlert, FlaskConical, CircleDollarSign, CheckCircle2 } from "lucide-react";
|
||||
import { getPolicyTemplates } from "@/components/networking";
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ const PolicyTemplates: React.FC<PolicyTemplatesProps> = ({
|
|||
onTemplatesLoaded?.(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching policy templates:", error);
|
||||
MessageManager.error("Failed to fetch policy templates");
|
||||
toast.error("Failed to fetch policy templates");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Modal, Form, Button, Typography } from "antd";
|
||||
import { FolderAddOutlined } from "@ant-design/icons";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { useCreateProject, ProjectCreateParams } from "@/app/(dashboard)/hooks/projects/useCreateProject";
|
||||
import { ProjectBaseForm, ProjectFormValues } from "./ProjectBaseForm";
|
||||
import { buildProjectApiParams } from "./projectFormUtils";
|
||||
|
|
@ -24,12 +24,12 @@ export function CreateProjectModal({ isOpen, onClose }: CreateProjectModalProps)
|
|||
|
||||
createMutation.mutate(params, {
|
||||
onSuccess: () => {
|
||||
MessageManager.success("Project created successfully");
|
||||
toast.success("Project created successfully");
|
||||
form.resetFields();
|
||||
onClose();
|
||||
},
|
||||
onError: (error) => {
|
||||
MessageManager.error(error.message || "Failed to create project");
|
||||
toast.error(error.message || "Failed to create project");
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useEffect } from "react";
|
||||
import { Modal, Form, Button, Typography } from "antd";
|
||||
import { SaveOutlined } from "@ant-design/icons";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { ProjectResponse } from "@/app/(dashboard)/hooks/projects/useProjects";
|
||||
import { useUpdateProject, ProjectUpdateParams } from "@/app/(dashboard)/hooks/projects/useUpdateProject";
|
||||
import { ProjectBaseForm, ProjectFormValues } from "./ProjectBaseForm";
|
||||
|
|
@ -72,12 +72,12 @@ export function EditProjectModal({ isOpen, project, onClose, onSuccess }: EditPr
|
|||
{ projectId: project.project_id, params },
|
||||
{
|
||||
onSuccess: () => {
|
||||
MessageManager.success("Project updated successfully");
|
||||
toast.success("Project updated successfully");
|
||||
onSuccess?.();
|
||||
onClose();
|
||||
},
|
||||
onError: (error) => {
|
||||
MessageManager.error(error.message || "Failed to update project");
|
||||
toast.error(error.message || "Failed to update project");
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { TextInput } from "@tremor/react";
|
|||
import { UploadOutlined } from "@ant-design/icons";
|
||||
import type { UploadFile, UploadProps } from "antd";
|
||||
import { convertPromptFileToJson, createPromptCall } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
|
|
@ -33,12 +33,12 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
|
|||
const values = await form.validateFields();
|
||||
|
||||
if (!accessToken) {
|
||||
NotificationsManager.fromBackend("Access token is required");
|
||||
toast.fromError("Access token is required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (promptIntegration === "dotprompt" && fileList.length === 0) {
|
||||
NotificationsManager.fromBackend("Please upload a .prompt file");
|
||||
toast.fromError("Please upload a .prompt file");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
|
|||
};
|
||||
} catch (conversionError) {
|
||||
console.error("Error converting prompt file:", conversionError);
|
||||
NotificationsManager.fromBackend("Failed to convert prompt file to JSON");
|
||||
toast.fromError("Failed to convert prompt file to JSON");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
|
@ -76,12 +76,12 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
|
|||
// Create the prompt
|
||||
try {
|
||||
await createPromptCall(accessToken, promptData);
|
||||
NotificationsManager.success("Prompt created successfully!");
|
||||
toast.success("Prompt created successfully!");
|
||||
handleCancel();
|
||||
onSuccess();
|
||||
} catch (createError) {
|
||||
console.error("Error creating prompt:", createError);
|
||||
NotificationsManager.fromBackend("Failed to create prompt");
|
||||
toast.fromError("Failed to create prompt");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Form validation error:", error);
|
||||
|
|
@ -93,7 +93,7 @@ const AddPromptForm: React.FC<AddPromptFormProps> = ({ visible, onClose, accessT
|
|||
const uploadProps: UploadProps = {
|
||||
beforeUpload: (file) => {
|
||||
if (!file.name.endsWith(".prompt")) {
|
||||
NotificationsManager.fromBackend("Please upload a .prompt file");
|
||||
toast.fromError("Please upload a .prompt file");
|
||||
return false;
|
||||
}
|
||||
return false; // Prevent automatic upload
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import PromptTable from "./PromptTable";
|
|||
import PromptInfoView from "./prompt_info";
|
||||
import AddPromptForm from "./add_prompt_form";
|
||||
import PromptEditorView from "./prompt_editor_view";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { isProxyAdminRole } from "@/utils/roles";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
|
|
@ -121,11 +121,11 @@ const PromptsPanel: React.FC<PromptsProps> = ({ accessToken, userRole }) => {
|
|||
setIsDeleting(true);
|
||||
try {
|
||||
await deletePromptCall(accessToken, promptToDelete.id);
|
||||
NotificationsManager.success(`Prompt "${promptToDelete.name}" deleted successfully`);
|
||||
toast.success(`Prompt "${promptToDelete.name}" deleted successfully`);
|
||||
fetchPrompts(); // Refresh the list
|
||||
} catch (error) {
|
||||
console.error("Error deleting prompt:", error);
|
||||
NotificationsManager.fromBackend("Failed to delete prompt");
|
||||
toast.fromError("Failed to delete prompt");
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
setPromptToDelete(null);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useState } from "react";
|
|||
import { CodeIcon, CopyIcon } from "lucide-react";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import { coy } from "react-syntax-highlighter/dist/esm/styles/prism";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
|
|
@ -269,7 +269,7 @@ main();`;
|
|||
variant="outline"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(generatedCode);
|
||||
NotificationsManager.success("Copied to clipboard!");
|
||||
toast.success("Copied to clipboard!");
|
||||
}}
|
||||
>
|
||||
<CopyIcon />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useRef, useEffect } from "react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { TokenUsage } from "@/components/chat_ui/ResponseMetrics";
|
||||
import { Message } from "./types";
|
||||
import { convertToDotPrompt, extractVariables } from "../utils";
|
||||
|
|
@ -37,12 +37,12 @@ export const useConversation = (prompt: any, accessToken: string | null) => {
|
|||
|
||||
const handleSendMessage = async () => {
|
||||
if (!accessToken) {
|
||||
NotificationsManager.fromBackend("Access token is required");
|
||||
toast.fromError("Access token is required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (extractedVariables.length > 0 && !allVariablesFilled) {
|
||||
NotificationsManager.fromBackend("Please fill in all template variables");
|
||||
toast.fromError("Please fill in all template variables");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -198,14 +198,14 @@ export const useConversation = (prompt: any, accessToken: string | null) => {
|
|||
abortController.abort();
|
||||
setAbortController(null);
|
||||
setIsLoading(false);
|
||||
NotificationsManager.info("Request cancelled");
|
||||
toast.info("Request cancelled");
|
||||
}
|
||||
};
|
||||
|
||||
const handleClearConversation = () => {
|
||||
setMessages([]);
|
||||
setVariablesFilled(false);
|
||||
NotificationsManager.success("Chat history cleared.");
|
||||
toast.success("Chat history cleared.");
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from "react";
|
||||
import ToolModal from "../tool_modal";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { createPromptCall, updatePromptCall, getPromptInfo } from "@/components/networking";
|
||||
import { PromptType, PromptEditorViewProps, Tool } from "./types";
|
||||
import { convertToDotPrompt, parseExistingPrompt } from "./utils";
|
||||
|
|
@ -21,7 +21,7 @@ const PromptEditorView: React.FC<PromptEditorViewProps> = ({ onClose, onSuccess,
|
|||
return parseExistingPrompt(initialPromptData);
|
||||
} catch (error) {
|
||||
console.error("Error parsing existing prompt:", error);
|
||||
NotificationsManager.fromBackend("Failed to parse prompt data");
|
||||
toast.fromError("Failed to parse prompt data");
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
|
@ -142,7 +142,7 @@ const PromptEditorView: React.FC<PromptEditorViewProps> = ({ onClose, onSuccess,
|
|||
setShowToolModal(false);
|
||||
setEditingToolIndex(null);
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend("Invalid JSON format");
|
||||
toast.fromError("Invalid JSON format");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -169,10 +169,9 @@ const PromptEditorView: React.FC<PromptEditorViewProps> = ({ onClose, onSuccess,
|
|||
// Store the version number or construct versioned ID for tracking
|
||||
const versionNum = versionData.version || 1;
|
||||
setActiveVersionId(`${versionData.prompt_id}.v${versionNum}`);
|
||||
// NotificationsManager.success(`Loaded version v${versionNum}`);
|
||||
} catch (error) {
|
||||
console.error("Error loading version:", error);
|
||||
NotificationsManager.fromBackend("Failed to load prompt version");
|
||||
toast.fromError("Failed to load prompt version");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -186,12 +185,12 @@ const PromptEditorView: React.FC<PromptEditorViewProps> = ({ onClose, onSuccess,
|
|||
|
||||
const handleSave = async () => {
|
||||
if (!accessToken) {
|
||||
NotificationsManager.fromBackend("Access token is required");
|
||||
toast.fromError("Access token is required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!prompt.name || prompt.name.trim() === "") {
|
||||
NotificationsManager.fromBackend("Please enter a valid prompt name");
|
||||
toast.fromError("Please enter a valid prompt name");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -215,16 +214,16 @@ const PromptEditorView: React.FC<PromptEditorViewProps> = ({ onClose, onSuccess,
|
|||
|
||||
if (editMode && initialPromptData?.prompt_spec?.prompt_id) {
|
||||
await updatePromptCall(accessToken, initialPromptData.prompt_spec.prompt_id, promptData);
|
||||
NotificationsManager.success("Prompt updated successfully!");
|
||||
toast.success("Prompt updated successfully!");
|
||||
} else {
|
||||
await createPromptCall(accessToken, promptData);
|
||||
NotificationsManager.success("Prompt created successfully!");
|
||||
toast.success("Prompt created successfully!");
|
||||
}
|
||||
onSuccess();
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error("Error saving prompt:", error);
|
||||
NotificationsManager.fromBackend(editMode ? "Failed to update prompt" : "Failed to save prompt");
|
||||
toast.fromError(editMode ? "Failed to update prompt" : "Failed to save prompt");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
setShowNameModal(false);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import {
|
|||
} from "@/components/networking";
|
||||
import { copyToClipboard as utilCopyToClipboard } from "@/utils/dataUtils";
|
||||
import { CheckIcon, CopyIcon } from "lucide-react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import PromptCodeSnippets from "./prompt_editor_view/PromptCodeSnippets";
|
||||
import { extractModel, extractTemplateVariables, getBasePromptId, getCurrentVersion } from "./prompt_utils";
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ const PromptInfoView: React.FC<PromptInfoProps> = ({ promptId, onClose, accessTo
|
|||
}
|
||||
setSelectedVersion(response.prompt_spec.version || null);
|
||||
} catch (error) {
|
||||
NotificationsManager.fromBackend("Failed to load prompt information");
|
||||
toast.fromError("Failed to load prompt information");
|
||||
console.error("Error fetching prompt info:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
|
@ -156,12 +156,12 @@ const PromptInfoView: React.FC<PromptInfoProps> = ({ promptId, onClose, accessTo
|
|||
setIsDeleting(true);
|
||||
try {
|
||||
await deletePromptCall(accessToken, basePromptId);
|
||||
NotificationsManager.success(`Prompt "${basePromptId}" deleted successfully`);
|
||||
toast.success(`Prompt "${basePromptId}" deleted successfully`);
|
||||
onDelete?.();
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error("Error deleting prompt:", error);
|
||||
NotificationsManager.fromBackend("Failed to delete prompt");
|
||||
toast.fromError("Failed to delete prompt");
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
setShowDeleteConfirm(false);
|
||||
|
|
@ -184,7 +184,7 @@ const PromptInfoView: React.FC<PromptInfoProps> = ({ promptId, onClose, accessTo
|
|||
setPromptTemplate(response.raw_prompt_template);
|
||||
setRawApiResponse(response);
|
||||
} catch {
|
||||
NotificationsManager.fromBackend(`Failed to load version v${versionNum}`);
|
||||
toast.fromError(`Failed to load version v${versionNum}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Button, TextInput } from "@tremor/react";
|
|||
import { Form, Input, Modal, Select, Tooltip, Typography } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { Logo } from "@/components/molecules/logo/Logo";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { createSearchTool, fetchAvailableSearchProviders } from "@/components/networking";
|
||||
import SearchConnectionTest from "./SearchConnectionTest";
|
||||
import { AvailableSearchProvider, SearchTool } from "./types";
|
||||
|
|
@ -98,14 +98,14 @@ const CreateSearchTool: React.FC<CreateSearchToolProps> = ({
|
|||
if (accessToken != null) {
|
||||
const response = await createSearchTool(accessToken, payload);
|
||||
|
||||
NotificationsManager.success("Search tool created successfully");
|
||||
toast.success("Search tool created successfully");
|
||||
form.resetFields();
|
||||
setFormValues({});
|
||||
setModalVisible(false);
|
||||
onCreateSuccess(response);
|
||||
}
|
||||
} catch (error) {
|
||||
NotificationsManager.error("Error creating search tool: " + error);
|
||||
toast.error("Error creating search tool: " + error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ const CreateSearchTool: React.FC<CreateSearchToolProps> = ({
|
|||
// Show the modal with the fresh test
|
||||
setIsTestModalVisible(true);
|
||||
} catch (error) {
|
||||
NotificationsManager.error("Please fill in Search Provider and API Key before testing");
|
||||
toast.error("Please fill in Search Provider and API Key before testing");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import userEvent from "@testing-library/user-event";
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import SearchConnectionTest from "./SearchConnectionTest";
|
||||
import * as networking from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
testSearchToolConnection: vi.fn(),
|
||||
|
|
@ -68,7 +68,7 @@ describe("SearchConnectionTest", () => {
|
|||
render(<SearchConnectionTest {...defaultProps} onTestComplete={onTestComplete} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(NotificationsManager.success).toHaveBeenCalledWith("Connection test successful!");
|
||||
expect(toast.success).toHaveBeenCalledWith("Connection test successful!");
|
||||
});
|
||||
expect(onTestComplete).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { AlertTriangle, CheckCircle2, Info } from "lucide-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { testSearchToolConnection } from "@/components/networking";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
|
|
@ -30,7 +30,7 @@ const SearchConnectionTest: React.FC<SearchConnectionTestProps> = ({ litellmPara
|
|||
const result = await testSearchToolConnection(accessToken, litellmParams);
|
||||
setTestResult(result);
|
||||
if (result.status === "success") {
|
||||
NotificationsManager.success("Connection test successful!");
|
||||
toast.success("Connection test successful!");
|
||||
}
|
||||
} catch (error) {
|
||||
setTestResult({
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import userEvent from "@testing-library/user-event";
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { SearchToolTester } from "./SearchToolTester";
|
||||
import * as networking from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
searchToolQueryCall: vi.fn(),
|
||||
|
|
@ -293,7 +293,7 @@ describe("SearchToolTester", () => {
|
|||
const searchButton = screen.getByRole("button", { name: /search/i });
|
||||
await user.click(searchButton);
|
||||
await waitFor(() => {
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith("Failed to query search tool");
|
||||
expect(toast.fromError).toHaveBeenCalledWith("Failed to query search tool");
|
||||
});
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
|
|
@ -360,7 +360,7 @@ describe("SearchToolTester", () => {
|
|||
});
|
||||
const clearButton = screen.getByRole("button", { name: /clear all/i });
|
||||
await user.click(clearButton);
|
||||
expect(NotificationsManager.success).toHaveBeenCalledWith("Search history cleared");
|
||||
expect(toast.success).toHaveBeenCalledWith("Search history cleared");
|
||||
expect(screen.queryByText("Previous Searches")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import React, { useState } from "react";
|
||||
import { ExternalLink, Search } from "lucide-react";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { searchToolQueryCall } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
|
@ -39,7 +38,7 @@ export const SearchToolTester: React.FC<SearchToolTesterProps> = ({ searchToolNa
|
|||
|
||||
const handleSearch = async () => {
|
||||
if (!query.trim()) {
|
||||
MessageManager.warning("Please enter a search query");
|
||||
toast.warning("Please enter a search query");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +60,7 @@ export const SearchToolTester: React.FC<SearchToolTesterProps> = ({ searchToolNa
|
|||
setSearchHistory((prev) => [historyEntry, ...prev]);
|
||||
} catch (error) {
|
||||
console.error("Error querying search tool:", error);
|
||||
NotificationsManager.fromBackend("Failed to query search tool");
|
||||
toast.fromError("Failed to query search tool");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
@ -74,7 +73,7 @@ export const SearchToolTester: React.FC<SearchToolTesterProps> = ({ searchToolNa
|
|||
const clearHistory = () => {
|
||||
setSearchHistory([]);
|
||||
setExpandedResults({});
|
||||
NotificationsManager.success("Search history cleared");
|
||||
toast.success("Search history cleared");
|
||||
};
|
||||
|
||||
const toggleResultExpansion = (historyIndex: number, resultIndex: number) => {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Button, Text, Title } from "@tremor/react";
|
|||
import { Form, Input, Modal, Select } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import {
|
||||
deleteSearchTool,
|
||||
fetchAvailableSearchProviders,
|
||||
|
|
@ -93,13 +93,13 @@ const SearchTools: React.FC<SearchToolsProps> = ({ accessToken, userRole, userID
|
|||
setIsDeleting(true);
|
||||
try {
|
||||
await deleteSearchTool(accessToken, toolIdToDelete);
|
||||
NotificationsManager.success("Deleted search tool successfully");
|
||||
toast.success("Deleted search tool successfully");
|
||||
setIsDeleteModalOpen(false);
|
||||
setToolToDelete(null);
|
||||
refetch();
|
||||
} catch (error) {
|
||||
console.error("Error deleting the search tool:", error);
|
||||
NotificationsManager.error("Failed to delete search tool");
|
||||
toast.error("Failed to delete search tool");
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
|
|
@ -142,14 +142,14 @@ const SearchTools: React.FC<SearchToolsProps> = ({ accessToken, userRole, userID
|
|||
};
|
||||
|
||||
await updateSearchTool(accessToken, selectedToolId, searchToolData);
|
||||
NotificationsManager.success("Search tool updated successfully");
|
||||
toast.success("Search tool updated successfully");
|
||||
setEditModalVisible(false);
|
||||
form.resetFields();
|
||||
setSelectedToolId(null);
|
||||
refetch();
|
||||
} catch (error) {
|
||||
console.error("Failed to update search tool:", error);
|
||||
NotificationsManager.error("Failed to update search tool");
|
||||
toast.error("Failed to update search tool");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import AddPluginForm from "./add_plugin_form";
|
|||
import PluginTable from "./PluginTable";
|
||||
import SkillDetail from "@/components/claude_code_plugins/skill_detail";
|
||||
import { isAdminRole } from "@/utils/roles";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { Plugin, ListPluginsResponse } from "@/components/claude_code_plugins/types";
|
||||
|
||||
interface ClaudeCodePluginsPanelProps {
|
||||
|
|
@ -66,11 +66,11 @@ const ClaudeCodePluginsPanel: React.FC<ClaudeCodePluginsPanelProps> = ({ accessT
|
|||
setIsDeleting(true);
|
||||
try {
|
||||
await deleteClaudeCodePlugin(accessToken, pluginToDelete.name);
|
||||
NotificationsManager.success(`Skill "${pluginToDelete.displayName}" deleted successfully`);
|
||||
toast.success(`Skill "${pluginToDelete.displayName}" deleted successfully`);
|
||||
fetchPlugins();
|
||||
} catch (error) {
|
||||
console.error("Error deleting skill:", error);
|
||||
NotificationsManager.error("Failed to delete skill");
|
||||
toast.error("Failed to delete skill");
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
setPluginToDelete(null);
|
||||
|
|
|
|||
|
|
@ -4,18 +4,14 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
|
|||
import { renderWithProviders } from "@/../tests/test-utils";
|
||||
import AddPluginForm from "./add_plugin_form";
|
||||
import { registerClaudeCodePlugin } from "@/components/networking";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
registerClaudeCodePlugin: vi.fn().mockResolvedValue({ status: "success" }),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/message_manager", () => ({
|
||||
default: { error: vi.fn(), success: vi.fn() },
|
||||
}));
|
||||
|
||||
const mockRegister = vi.mocked(registerClaudeCodePlugin);
|
||||
const mockMessageError = vi.mocked(MessageManager.error);
|
||||
const mockMessageError = vi.mocked(toast.error);
|
||||
|
||||
const DEFAULT_PROPS = {
|
||||
visible: true,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useState } from "react";
|
|||
import { Modal } from "antd";
|
||||
import { CircleHelp } from "lucide-react";
|
||||
import { z } from "zod/v4";
|
||||
import MessageManager from "@/components/molecules/message_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { registerClaudeCodePlugin } from "@/components/networking";
|
||||
import { FieldGroup } from "@/components/shared/form/field";
|
||||
import { FormField } from "@/components/shared/form/FormField";
|
||||
|
|
@ -146,34 +146,34 @@ const AddPluginForm: React.FC<AddPluginFormProps> = ({ visible, onClose, accessT
|
|||
|
||||
const handleSubmit = async (values: AddPluginFormValues) => {
|
||||
if (!accessToken) {
|
||||
MessageManager.error("No access token available");
|
||||
toast.error("No access token available");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!urlPreview) {
|
||||
MessageManager.error("Please enter a valid repository URL");
|
||||
toast.error("Please enter a valid repository URL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validatePluginName(values.name)) {
|
||||
MessageManager.error("Skill name must be kebab-case (lowercase letters, numbers, and hyphens only)");
|
||||
toast.error("Skill name must be kebab-case (lowercase letters, numbers, and hyphens only)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.version && !isValidSemanticVersion(values.version)) {
|
||||
MessageManager.error("Version must be in semantic versioning format (e.g., 1.0.0)");
|
||||
toast.error("Version must be in semantic versioning format (e.g., 1.0.0)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.authorEmail && !isValidEmail(values.authorEmail)) {
|
||||
MessageManager.error("Invalid email format");
|
||||
toast.error("Invalid email format");
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
await registerClaudeCodePlugin(accessToken, buildRegisterRequest(values, urlPreview.parsed));
|
||||
MessageManager.success("Skill registered successfully");
|
||||
toast.success("Skill registered successfully");
|
||||
form.reset(EMPTY_VALUES);
|
||||
setUrlPreview(null);
|
||||
setUrlEncodesSubdir(false);
|
||||
|
|
@ -181,7 +181,7 @@ const AddPluginForm: React.FC<AddPluginFormProps> = ({ visible, onClose, accessT
|
|||
onClose();
|
||||
} catch (error) {
|
||||
console.error("Error registering skill:", error);
|
||||
MessageManager.error(error instanceof Error && error.message ? error.message : "Failed to register skill");
|
||||
toast.error(error instanceof Error && error.message ? error.message : "Failed to register skill");
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,14 +13,6 @@ vi.mock("@/components/networking", () => ({
|
|||
modelInfoCall: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
success: vi.fn(),
|
||||
fromBackend: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("./TagTable", () => ({
|
||||
__esModule: true,
|
||||
default: ({ isLoading, onDelete }: { isLoading?: boolean; onDelete: (tagName: string) => void }) => (
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { modelInfoCall } from "@/components/networking";
|
|||
import { tagCreateCall, tagListCall, tagDeleteCall } from "@/components/networking";
|
||||
import { Tag } from "@/components/tag_management/types";
|
||||
import TagTable from "./TagTable";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import DeleteResourceModal from "@/components/common_components/DeleteResourceModal";
|
||||
import CreateTagModal from "./components/CreateTagModal";
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ const TagManagement: React.FC<TagProps> = ({ accessToken, userID, userRole }) =>
|
|||
setTags(Object.values(response));
|
||||
} catch (error) {
|
||||
console.error("Error fetching tags:", error);
|
||||
NotificationsManager.fromBackend("Error fetching tags: " + error);
|
||||
toast.fromError("Error fetching tags: " + error);
|
||||
} finally {
|
||||
setIsLoadingTags(false);
|
||||
}
|
||||
|
|
@ -73,12 +73,12 @@ const TagManagement: React.FC<TagProps> = ({ accessToken, userID, userRole }) =>
|
|||
rpm_limit: formValues.rpm_limit,
|
||||
budget_duration: formValues.budget_duration,
|
||||
});
|
||||
NotificationsManager.success("Tag created successfully");
|
||||
toast.success("Tag created successfully");
|
||||
setIsCreateModalVisible(false);
|
||||
fetchTags();
|
||||
} catch (error) {
|
||||
console.error("Error creating tag:", error);
|
||||
NotificationsManager.fromBackend("Error creating tag: " + error);
|
||||
toast.fromError("Error creating tag: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -92,11 +92,11 @@ const TagManagement: React.FC<TagProps> = ({ accessToken, userID, userRole }) =>
|
|||
setIsDeleting(true);
|
||||
try {
|
||||
await tagDeleteCall(accessToken, tagToDelete);
|
||||
NotificationsManager.success("Tag deleted successfully");
|
||||
toast.success("Tag deleted successfully");
|
||||
fetchTags();
|
||||
} catch (error) {
|
||||
console.error("Error deleting tag:", error);
|
||||
NotificationsManager.fromBackend("Error deleting tag: " + error);
|
||||
toast.fromError("Error deleting tag: " + error);
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
setIsDeleteModalOpen(false);
|
||||
|
|
@ -114,7 +114,7 @@ const TagManagement: React.FC<TagProps> = ({ accessToken, userID, userRole }) =>
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching models:", error);
|
||||
NotificationsManager.fromBackend("Error fetching models: " + error);
|
||||
toast.fromError("Error fetching models: " + error);
|
||||
}
|
||||
};
|
||||
fetchModels();
|
||||
|
|
|
|||
|
|
@ -21,11 +21,6 @@ vi.mock("@/components/organisms/create_key_button", () => ({
|
|||
),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
__esModule: true,
|
||||
default: { success: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
const mockTagInfoCall = vi.mocked(tagInfoCall);
|
||||
const mockTagUpdateCall = vi.mocked(tagUpdateCall);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { fetchUserModels } from "@/components/organisms/create_key_button";
|
|||
import { getModelDisplayName } from "@/components/key_team_helpers/fetch_available_models_team_key";
|
||||
import { tagInfoCall, tagUpdateCall } from "@/components/networking";
|
||||
import { Tag, TagUpdateRequest } from "@/components/tag_management/types";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
import NumericalInput from "@/components/shared/numerical_input";
|
||||
import BudgetDurationDropdown from "@/components/common_components/budget_duration_dropdown";
|
||||
import { FieldGroup } from "@/components/shared/form/field";
|
||||
|
|
@ -175,7 +175,7 @@ const TagInfoView: React.FC<TagInfoViewProps> = ({ tagId, onClose, accessToken,
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching tag details:", error);
|
||||
NotificationsManager.fromBackend("Error fetching tag details: " + error);
|
||||
toast.fromError("Error fetching tag details: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -203,12 +203,12 @@ const TagInfoView: React.FC<TagInfoViewProps> = ({ tagId, onClose, accessToken,
|
|||
rpm_limit: undefined,
|
||||
budget_duration: values.budget_duration,
|
||||
});
|
||||
NotificationsManager.success("Tag updated successfully");
|
||||
toast.success("Tag updated successfully");
|
||||
setIsEditing(false);
|
||||
fetchTagDetails();
|
||||
} catch (error) {
|
||||
console.error("Error updating tag:", error);
|
||||
NotificationsManager.fromBackend("Error updating tag: " + error);
|
||||
toast.fromError("Error updating tag: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,22 +3,14 @@ import userEvent from "@testing-library/user-event";
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import TransformRequestPanel from "./TransformRequestPanel";
|
||||
import { transformRequestCall } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
transformRequestCall: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
default: {
|
||||
success: vi.fn(),
|
||||
info: vi.fn(),
|
||||
fromBackend: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const transformRequestCallMock = vi.mocked(transformRequestCall);
|
||||
const notify = vi.mocked(NotificationsManager);
|
||||
const notify = vi.mocked(toast);
|
||||
|
||||
const ACCESS_TOKEN = "sk-test-token";
|
||||
|
||||
|
|
@ -109,7 +101,7 @@ describe("TransformRequestPanel", () => {
|
|||
await user.type(textarea, "not json");
|
||||
await user.click(getTransformButton());
|
||||
|
||||
await waitFor(() => expect(notify.fromBackend).toHaveBeenCalledWith("Invalid JSON in request body"));
|
||||
await waitFor(() => expect(notify.fromError).toHaveBeenCalledWith("Invalid JSON in request body"));
|
||||
expect(transformRequestCallMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
|
@ -120,7 +112,7 @@ describe("TransformRequestPanel", () => {
|
|||
|
||||
await user.click(getTransformButton());
|
||||
|
||||
await waitFor(() => expect(notify.fromBackend).toHaveBeenCalledWith("No access token found"));
|
||||
await waitFor(() => expect(notify.fromError).toHaveBeenCalledWith("No access token found"));
|
||||
expect(transformRequestCallMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
|
@ -133,7 +125,7 @@ describe("TransformRequestPanel", () => {
|
|||
|
||||
await user.click(getTransformButton());
|
||||
|
||||
await waitFor(() => expect(notify.fromBackend).toHaveBeenCalledWith("Failed to transform request"));
|
||||
await waitFor(() => expect(notify.fromError).toHaveBeenCalledWith("Failed to transform request"));
|
||||
expect(screen.getByText(/https:\/\/api\.openai\.com\/v1\/chat\/completions/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }
|
|||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { UiLoadingSpinner } from "@/components/ui/ui-loading-spinner";
|
||||
import { transformRequestCall } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
interface TransformRequestPanelProps {
|
||||
accessToken: string | null;
|
||||
|
|
@ -69,7 +69,7 @@ ${formattedBody}
|
|||
try {
|
||||
requestBody = JSON.parse(originalRequestJSON);
|
||||
} catch (e) {
|
||||
NotificationsManager.fromBackend("Invalid JSON in request body");
|
||||
toast.fromError("Invalid JSON in request body");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ ${formattedBody}
|
|||
|
||||
// Make the API call using fetch
|
||||
if (!accessToken) {
|
||||
NotificationsManager.fromBackend("No access token found");
|
||||
toast.fromError("No access token found");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
|
@ -100,17 +100,17 @@ ${formattedBody}
|
|||
|
||||
// Update state with the formatted curl command
|
||||
setTransformedResponse(formattedCurl);
|
||||
NotificationsManager.success("Request transformed successfully");
|
||||
toast.success("Request transformed successfully");
|
||||
} else {
|
||||
// Handle the case where the API returns a different format
|
||||
// Try to extract the parts from a string response if needed
|
||||
const rawText = typeof data === "string" ? data : JSON.stringify(data);
|
||||
setTransformedResponse(rawText);
|
||||
NotificationsManager.info("Transformed request received in unexpected format");
|
||||
toast.info("Transformed request received in unexpected format");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error transforming request:", err);
|
||||
NotificationsManager.fromBackend("Failed to transform request");
|
||||
toast.fromError("Failed to transform request");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
@ -191,7 +191,7 @@ ${formattedBody}
|
|||
className="absolute top-2 right-2"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(transformedResponse || "");
|
||||
NotificationsManager.success("Copied to clipboard");
|
||||
toast.success("Copied to clipboard");
|
||||
}}
|
||||
>
|
||||
<Copy />
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { render, screen, waitFor } from "@testing-library/react";
|
|||
import userEvent from "@testing-library/user-event";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
import UIThemeSettings from "./UIThemeSettings";
|
||||
|
||||
|
|
@ -18,11 +18,6 @@ vi.mock("@/components/networking", () => ({
|
|||
getGlobalLitellmHeaderName: () => "Authorization",
|
||||
}));
|
||||
|
||||
vi.mock("@/components/molecules/notifications_manager", () => ({
|
||||
__esModule: true,
|
||||
default: { success: vi.fn(), fromBackend: vi.fn() },
|
||||
}));
|
||||
|
||||
const LOGO_PLACEHOLDER = "https://example.com/logo.png";
|
||||
const FAVICON_PLACEHOLDER = "https://example.com/favicon.ico";
|
||||
|
||||
|
|
@ -83,9 +78,7 @@ describe("UIThemeSettings", () => {
|
|||
logo_url: "https://a.test/logo.png",
|
||||
favicon_url: "https://a.test/fav.ico",
|
||||
});
|
||||
await waitFor(() =>
|
||||
expect(NotificationsManager.success).toHaveBeenCalledWith("Theme settings updated successfully!"),
|
||||
);
|
||||
await waitFor(() => expect(toast.success).toHaveBeenCalledWith("Theme settings updated successfully!"));
|
||||
});
|
||||
|
||||
it("should surface a backend failure when saving fails", async () => {
|
||||
|
|
@ -97,10 +90,8 @@ describe("UIThemeSettings", () => {
|
|||
|
||||
await user.click(screen.getByRole("button", { name: "Save Changes" }));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(NotificationsManager.fromBackend).toHaveBeenCalledWith("Failed to update theme settings"),
|
||||
);
|
||||
expect(NotificationsManager.success).not.toHaveBeenCalled();
|
||||
await waitFor(() => expect(toast.fromError).toHaveBeenCalledWith("Failed to update theme settings"));
|
||||
expect(toast.success).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should clear both inputs and persist nulls when resetting to default", async () => {
|
||||
|
|
@ -123,6 +114,6 @@ describe("UIThemeSettings", () => {
|
|||
expect(screen.getByPlaceholderText(FAVICON_PLACEHOLDER)).toHaveValue("");
|
||||
expect(setLogoUrl).toHaveBeenLastCalledWith(null);
|
||||
expect(setFaviconUrl).toHaveBeenLastCalledWith(null);
|
||||
await waitFor(() => expect(NotificationsManager.success).toHaveBeenCalledWith("Theme settings reset to default!"));
|
||||
await waitFor(() => expect(toast.success).toHaveBeenCalledWith("Theme settings reset to default!"));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { Label } from "@/components/ui/label";
|
|||
import { UiLoadingSpinner } from "@/components/ui/ui-loading-spinner";
|
||||
import { useTheme } from "@/contexts/ThemeContext";
|
||||
import { getProxyBaseUrl, getGlobalLitellmHeaderName } from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { toast } from "@/lib/toast";
|
||||
|
||||
interface UIThemeSettingsProps {
|
||||
userID: string | null;
|
||||
|
|
@ -66,7 +66,7 @@ const UIThemeSettings: React.FC<UIThemeSettingsProps> = ({ userID, userRole, acc
|
|||
}),
|
||||
});
|
||||
if (response.ok) {
|
||||
NotificationsManager.success("Theme settings updated successfully!");
|
||||
toast.success("Theme settings updated successfully!");
|
||||
setLogoUrl(logoUrlInput || null);
|
||||
setFaviconUrl(faviconUrlInput || null);
|
||||
} else {
|
||||
|
|
@ -74,7 +74,7 @@ const UIThemeSettings: React.FC<UIThemeSettingsProps> = ({ userID, userRole, acc
|
|||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating theme settings:", error);
|
||||
NotificationsManager.fromBackend("Failed to update theme settings");
|
||||
toast.fromError("Failed to update theme settings");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -98,13 +98,13 @@ const UIThemeSettings: React.FC<UIThemeSettingsProps> = ({ userID, userRole, acc
|
|||
body: JSON.stringify({ logo_url: null, favicon_url: null }),
|
||||
});
|
||||
if (response.ok) {
|
||||
NotificationsManager.success("Theme settings reset to default!");
|
||||
toast.success("Theme settings reset to default!");
|
||||
} else {
|
||||
throw new Error("Failed to reset");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error resetting theme settings:", error);
|
||||
NotificationsManager.fromBackend("Failed to reset theme settings");
|
||||
toast.fromError("Failed to reset theme settings");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue