feat ui: support import provider from template

This commit is contained in:
musistudio
2025-08-02 22:56:18 +08:00
parent cd43a74ab5
commit 996a05d1d6
10 changed files with 161 additions and 104 deletions

View File

@@ -1,53 +1,7 @@
import { createContext, useContext, useState, useEffect } from 'react'; import { createContext, useContext, useState, useEffect } from 'react';
import type { ReactNode, Dispatch, SetStateAction } from 'react'; import type { ReactNode, Dispatch, SetStateAction } from 'react';
import { api } from '@/lib/api'; import { api } from '@/lib/api';
import type { Config } from '@/types';
export interface Transformer {
path: string;
options: {
[key: string]: string;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
}
export interface ProviderTransformer {
use: (string | (string | Record<string, unknown> | { max_tokens: number })[])[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any; // for model specific transformers
}
export interface Provider {
name: string;
api_base_url: string;
api_key: string;
models: string[];
transformer?: ProviderTransformer;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
}
export interface RouterConfig {
default: string;
background: string;
think: string;
longContext: string;
longContextThreshold: number;
webSearch: string;
}
export interface Config {
LOG: boolean;
CLAUDE_PATH: string;
HOST: string;
PORT: number;
APIKEY: string;
API_TIMEOUT_MS: string;
PROXY_URL: string;
transformers: Transformer[];
Providers: Provider[];
Router: RouterConfig;
}
interface ConfigContextType { interface ConfigContextType {
config: Config | null; config: Config | null;
@@ -121,7 +75,7 @@ export function ConfigProvider({ children }: ConfigProviderProps) {
APIKEY: typeof data.APIKEY === 'string' ? data.APIKEY : '', APIKEY: typeof data.APIKEY === 'string' ? data.APIKEY : '',
API_TIMEOUT_MS: typeof data.API_TIMEOUT_MS === 'string' ? data.API_TIMEOUT_MS : '600000', API_TIMEOUT_MS: typeof data.API_TIMEOUT_MS === 'string' ? data.API_TIMEOUT_MS : '600000',
PROXY_URL: typeof data.PROXY_URL === 'string' ? data.PROXY_URL : '', PROXY_URL: typeof data.PROXY_URL === 'string' ? data.PROXY_URL : '',
transformers: Array.isArray(data.transformers) ? data.transformers : [], Transformers: Array.isArray(data.Transformers) ? data.Transformers : [],
Providers: Array.isArray(data.Providers) ? data.Providers : [], Providers: Array.isArray(data.Providers) ? data.Providers : [],
Router: data.Router && typeof data.Router === 'object' ? { Router: data.Router && typeof data.Router === 'object' ? {
default: typeof data.Router.default === 'string' ? data.Router.default : '', default: typeof data.Router.default === 'string' ? data.Router.default : '',
@@ -155,7 +109,7 @@ export function ConfigProvider({ children }: ConfigProviderProps) {
APIKEY: '', APIKEY: '',
API_TIMEOUT_MS: '600000', API_TIMEOUT_MS: '600000',
PROXY_URL: '', PROXY_URL: '',
transformers: [], Transformers: [],
Providers: [], Providers: [],
Router: { Router: {
default: '', default: '',

View File

@@ -1,7 +1,7 @@
import { Pencil, Trash2 } from "lucide-react"; import { Pencil, Trash2 } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { type Provider } from "./ConfigProvider"; import type { Provider } from "@/types";
interface ProviderListProps { interface ProviderListProps {
providers: Provider[]; providers: Provider[];

View File

@@ -19,7 +19,9 @@ import { Badge } from "@/components/ui/badge";
import { Combobox } from "@/components/ui/combobox"; import { Combobox } from "@/components/ui/combobox";
import { ComboInput } from "@/components/ui/combo-input"; import { ComboInput } from "@/components/ui/combo-input";
import { api } from "@/lib/api"; import { api } from "@/lib/api";
import type { Provider } from "@/types";
interface ProviderType extends Provider {}
export function Providers() { export function Providers() {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -30,10 +32,29 @@ export function Providers() {
const [providerParamInputs, setProviderParamInputs] = useState<Record<string, {name: string, value: string}>>({}); const [providerParamInputs, setProviderParamInputs] = useState<Record<string, {name: string, value: string}>>({});
const [modelParamInputs, setModelParamInputs] = useState<Record<string, {name: string, value: string}>>({}); const [modelParamInputs, setModelParamInputs] = useState<Record<string, {name: string, value: string}>>({});
const [availableTransformers, setAvailableTransformers] = useState<{name: string; endpoint: string | null;}[]>([]); const [availableTransformers, setAvailableTransformers] = useState<{name: string; endpoint: string | null;}[]>([]);
const [editingProviderData, setEditingProviderData] = useState<any>(null); const [editingProviderData, setEditingProviderData] = useState<ProviderType | null>(null);
const [isNewProvider, setIsNewProvider] = useState<boolean>(false); const [isNewProvider, setIsNewProvider] = useState<boolean>(false);
const [providerTemplates, setProviderTemplates] = useState<ProviderType[]>([]);
const comboInputRef = useRef<HTMLInputElement>(null); const comboInputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const fetchProviderTemplates = async () => {
try {
const response = await fetch('https://pub-0dc3e1677e894f07bbea11b17a29e032.r2.dev/providers.json');
if (response.ok) {
const data = await response.json();
setProviderTemplates(data || []);
} else {
console.error('Failed to fetch provider templates');
}
} catch (error) {
console.error('Failed to fetch provider templates:', error);
}
};
fetchProviderTemplates();
}, []);
// Fetch available transformers when component mounts // Fetch available transformers when component mounts
useEffect(() => { useEffect(() => {
const fetchTransformers = async () => { const fetchTransformers = async () => {
@@ -67,7 +88,7 @@ export function Providers() {
const handleAddProvider = () => { const handleAddProvider = () => {
const newProvider = { name: "", api_base_url: "", api_key: "", models: [] }; const newProvider: ProviderType = { name: "", api_base_url: "", api_key: "", models: [] };
setEditingProviderIndex(config.Providers.length); setEditingProviderIndex(config.Providers.length);
setEditingProviderData(newProvider); setEditingProviderData(newProvider);
setIsNewProvider(true); setIsNewProvider(true);
@@ -116,14 +137,14 @@ export function Providers() {
setDeletingProviderIndex(null); setDeletingProviderIndex(null);
}; };
const handleProviderChange = (index: number, field: string, value: string) => { const handleProviderChange = (_index: number, field: string, value: string) => {
if (editingProviderData) { if (editingProviderData) {
const updatedProvider = { ...editingProviderData, [field]: value }; const updatedProvider = { ...editingProviderData, [field]: value };
setEditingProviderData(updatedProvider); setEditingProviderData(updatedProvider);
} }
}; };
const handleProviderTransformerChange = (index: number, transformerPath: string) => { const handleProviderTransformerChange = (_index: number, transformerPath: string) => {
if (!transformerPath || !editingProviderData) return; // Don't add empty transformers if (!transformerPath || !editingProviderData) return; // Don't add empty transformers
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -137,7 +158,7 @@ export function Providers() {
setEditingProviderData(updatedProvider); setEditingProviderData(updatedProvider);
}; };
const removeProviderTransformerAtIndex = (index: number, transformerIndex: number) => { const removeProviderTransformerAtIndex = (_index: number, transformerIndex: number) => {
if (!editingProviderData) return; if (!editingProviderData) return;
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -156,7 +177,7 @@ export function Providers() {
setEditingProviderData(updatedProvider); setEditingProviderData(updatedProvider);
}; };
const handleModelTransformerChange = (providerIndex: number, model: string, transformerPath: string) => { const handleModelTransformerChange = (_providerIndex: number, model: string, transformerPath: string) => {
if (!transformerPath || !editingProviderData) return; // Don't add empty transformers if (!transformerPath || !editingProviderData) return; // Don't add empty transformers
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -175,7 +196,7 @@ export function Providers() {
setEditingProviderData(updatedProvider); setEditingProviderData(updatedProvider);
}; };
const removeModelTransformerAtIndex = (providerIndex: number, model: string, transformerIndex: number) => { const removeModelTransformerAtIndex = (_providerIndex: number, model: string, transformerIndex: number) => {
if (!editingProviderData) return; if (!editingProviderData) return;
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -195,7 +216,7 @@ export function Providers() {
}; };
const addProviderTransformerParameter = (providerIndex: number, transformerIndex: number, paramName: string, paramValue: string) => { const addProviderTransformerParameter = (_providerIndex: number, transformerIndex: number, paramName: string, paramValue: string) => {
if (!editingProviderData) return; if (!editingProviderData) return;
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -239,7 +260,7 @@ export function Providers() {
}; };
const removeProviderTransformerParameterAtIndex = (providerIndex: number, transformerIndex: number, paramName: string) => { const removeProviderTransformerParameterAtIndex = (_providerIndex: number, transformerIndex: number, paramName: string) => {
if (!editingProviderData) return; if (!editingProviderData) return;
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -269,7 +290,7 @@ export function Providers() {
} }
}; };
const addModelTransformerParameter = (providerIndex: number, model: string, transformerIndex: number, paramName: string, paramValue: string) => { const addModelTransformerParameter = (_providerIndex: number, model: string, transformerIndex: number, paramName: string, paramValue: string) => {
if (!editingProviderData) return; if (!editingProviderData) return;
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -317,7 +338,7 @@ export function Providers() {
}; };
const removeModelTransformerParameterAtIndex = (providerIndex: number, model: string, transformerIndex: number, paramName: string) => { const removeModelTransformerParameterAtIndex = (_providerIndex: number, model: string, transformerIndex: number, paramName: string) => {
if (!editingProviderData) return; if (!editingProviderData) return;
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -347,7 +368,7 @@ export function Providers() {
} }
}; };
const handleAddModel = (index: number, model: string) => { const handleAddModel = (_index: number, model: string) => {
if (!model.trim() || !editingProviderData) return; if (!model.trim() || !editingProviderData) return;
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -363,7 +384,26 @@ export function Providers() {
} }
}; };
const handleRemoveModel = (providerIndex: number, modelIndex: number) => { const handleTemplateImport = (value: string) => {
if (!value) return;
try {
const selectedTemplate = JSON.parse(value);
if (selectedTemplate) {
const currentName = editingProviderData?.name;
const newProviderData = JSON.parse(JSON.stringify(selectedTemplate));
if (!isNewProvider && currentName) {
newProviderData.name = currentName;
}
setEditingProviderData(newProviderData as ProviderType);
}
} catch (e) {
console.error("Failed to parse template", e);
}
};
const handleRemoveModel = (_providerIndex: number, modelIndex: number) => {
if (!editingProviderData) return; if (!editingProviderData) return;
const updatedProvider = { ...editingProviderData }; const updatedProvider = { ...editingProviderData };
@@ -407,6 +447,18 @@ export function Providers() {
</DialogHeader> </DialogHeader>
{editingProvider && editingProviderIndex !== null && ( {editingProvider && editingProviderIndex !== null && (
<div className="space-y-4 p-4 overflow-y-auto flex-grow"> <div className="space-y-4 p-4 overflow-y-auto flex-grow">
{providerTemplates.length > 0 && (
<div className="space-y-2">
<Label>{t("providers.import_from_template")}</Label>
<Combobox
options={providerTemplates.map(p => ({ label: p.name, value: JSON.stringify(p) }))}
value=""
onChange={handleTemplateImport}
placeholder={t("providers.select_template")}
emptyPlaceholder={t("providers.no_templates_found")}
/>
</div>
)}
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="name">{t("providers.name")}</Label> <Label htmlFor="name">{t("providers.name")}</Label>
<Input id="name" value={editingProvider.name || ''} onChange={(e) => handleProviderChange(editingProviderIndex, 'name', e.target.value)} /> <Input id="name" value={editingProvider.name || ''} onChange={(e) => handleProviderChange(editingProviderIndex, 'name', e.target.value)} />

View File

@@ -1,6 +1,6 @@
import { Pencil, Trash2 } from "lucide-react"; import { Pencil, Trash2 } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { type Transformer } from "./ConfigProvider"; import type { Transformer } from "@/types";
interface TransformerListProps { interface TransformerListProps {
transformers: Transformer[]; transformers: Transformer[];
@@ -46,8 +46,8 @@ export function TransformerList({ transformers, onEdit, onRemove }: TransformerL
// Handle case where transformer.path might be null or undefined // Handle case where transformer.path might be null or undefined
const transformerPath = transformer.path || "Unnamed Transformer"; const transformerPath = transformer.path || "Unnamed Transformer";
// Handle case where transformer.options might be null or undefined // Handle case where transformer.parameters might be null or undefined
const options = transformer.options || {}; const options = transformer.parameters || {};
// Render parameters as tags in a single line // Render parameters as tags in a single line
const renderParameters = () => { const renderParameters = () => {

View File

@@ -21,7 +21,7 @@ export function Transformers() {
const { config, setConfig } = useConfig(); const { config, setConfig } = useConfig();
const [editingTransformerIndex, setEditingTransformerIndex] = useState<number | null>(null); const [editingTransformerIndex, setEditingTransformerIndex] = useState<number | null>(null);
const [deletingTransformerIndex, setDeletingTransformerIndex] = useState<number | null>(null); const [deletingTransformerIndex, setDeletingTransformerIndex] = useState<number | null>(null);
const [newTransformer, setNewTransformer] = useState<{ path: string; options: { [key: string]: string } } | null>(null); const [newTransformer, setNewTransformer] = useState<{ name: string; path: string; project: string; parameters: { [key: string]: string } } | null>(null);
// Handle case where config is null or undefined // Handle case where config is null or undefined
if (!config) { if (!config) {
@@ -37,11 +37,11 @@ export function Transformers() {
); );
} }
// Validate config.transformers to ensure it's an array // Validate config.Transformers to ensure it's an array
const validTransformers = Array.isArray(config.transformers) ? config.transformers : []; const validTransformers = Array.isArray(config.Transformers) ? config.Transformers : [];
const handleAddTransformer = () => { const handleAddTransformer = () => {
const newTransformer = { path: "", options: {} }; const newTransformer = { name: "", path: "", project: "", parameters: {} };
setNewTransformer(newTransformer); setNewTransformer(newTransformer);
setEditingTransformerIndex(validTransformers.length); // Use the length as index for the new item setEditingTransformerIndex(validTransformers.length); // Use the length as index for the new item
}; };
@@ -49,26 +49,26 @@ export function Transformers() {
const handleRemoveTransformer = (index: number) => { const handleRemoveTransformer = (index: number) => {
const newTransformers = [...validTransformers]; const newTransformers = [...validTransformers];
newTransformers.splice(index, 1); newTransformers.splice(index, 1);
setConfig({ ...config, transformers: newTransformers }); setConfig({ ...config, Transformers: newTransformers });
setDeletingTransformerIndex(null); setDeletingTransformerIndex(null);
}; };
const handleTransformerChange = (index: number, field: string, value: string, optionKey?: string) => { const handleTransformerChange = (index: number, field: string, value: string, parameterKey?: string) => {
if (index < validTransformers.length) { if (index < validTransformers.length) {
// Editing an existing transformer // Editing an existing transformer
const newTransformers = [...validTransformers]; const newTransformers = [...validTransformers];
if (optionKey !== undefined) { if (parameterKey !== undefined) {
newTransformers[index].options[optionKey] = value; newTransformers[index].parameters![parameterKey] = value;
} else { } else {
(newTransformers[index] as Record<string, unknown>)[field] = value; (newTransformers[index] as unknown as Record<string, unknown>)[field] = value;
} }
setConfig({ ...config, transformers: newTransformers }); setConfig({ ...config, Transformers: newTransformers });
} else { } else {
// Editing the new transformer // Editing the new transformer
if (newTransformer) { if (newTransformer) {
const updatedTransformer = { ...newTransformer }; const updatedTransformer = { ...newTransformer };
if (optionKey !== undefined) { if (parameterKey !== undefined) {
updatedTransformer.options[optionKey] = value; updatedTransformer.parameters![parameterKey] = value;
} else { } else {
(updatedTransformer as Record<string, unknown>)[field] = value; (updatedTransformer as Record<string, unknown>)[field] = value;
} }
@@ -87,7 +87,7 @@ export function Transformers() {
if (newTransformer && editingTransformerIndex === validTransformers.length) { if (newTransformer && editingTransformerIndex === validTransformers.length) {
// Saving a new transformer // Saving a new transformer
const newTransformers = [...validTransformers, newTransformer]; const newTransformers = [...validTransformers, newTransformer];
setConfig({ ...config, transformers: newTransformers }); setConfig({ ...config, Transformers: newTransformers });
} }
// Close the dialog // Close the dialog
setEditingTransformerIndex(null); setEditingTransformerIndex(null);
@@ -137,16 +137,16 @@ export function Transformers() {
variant="outline" variant="outline"
size="sm" size="sm"
onClick={() => { onClick={() => {
const options = editingTransformer.options || {}; const parameters = editingTransformer.parameters || {};
const newKey = `param${Object.keys(options).length + 1}`; const newKey = `param${Object.keys(parameters).length + 1}`;
if (editingTransformerIndex !== null) { if (editingTransformerIndex !== null) {
const newOptions = { ...options, [newKey]: "" }; const newParameters = { ...parameters, [newKey]: "" };
if (editingTransformerIndex < validTransformers.length) { if (editingTransformerIndex < validTransformers.length) {
const newTransformers = [...validTransformers]; const newTransformers = [...validTransformers];
newTransformers[editingTransformerIndex].options = newOptions; newTransformers[editingTransformerIndex].parameters = newParameters;
setConfig({ ...config, transformers: newTransformers }); setConfig({ ...config, Transformers: newTransformers });
} else if (newTransformer) { } else if (newTransformer) {
setNewTransformer({ ...newTransformer, options: newOptions }); setNewTransformer({ ...newTransformer, parameters: newParameters });
} }
} }
}} }}
@@ -154,22 +154,22 @@ export function Transformers() {
<Plus className="h-4 w-4" /> <Plus className="h-4 w-4" />
</Button> </Button>
</div> </div>
{Object.entries(editingTransformer.options || {}).map(([key, value]) => ( {Object.entries(editingTransformer.parameters || {}).map(([key, value]) => (
<div key={key} className="flex items-center gap-2"> <div key={key} className="flex items-center gap-2">
<Input <Input
value={key} value={key}
onChange={(e) => { onChange={(e) => {
const options = editingTransformer.options || {}; const parameters = editingTransformer.parameters || {};
const newOptions = { ...options }; const newParameters = { ...parameters };
delete newOptions[key]; delete newParameters[key];
newOptions[e.target.value] = value; newParameters[e.target.value] = value;
if (editingTransformerIndex !== null) { if (editingTransformerIndex !== null) {
if (editingTransformerIndex < validTransformers.length) { if (editingTransformerIndex < validTransformers.length) {
const newTransformers = [...validTransformers]; const newTransformers = [...validTransformers];
newTransformers[editingTransformerIndex].options = newOptions; newTransformers[editingTransformerIndex].parameters = newParameters;
setConfig({ ...config, transformers: newTransformers }); setConfig({ ...config, Transformers: newTransformers });
} else if (newTransformer) { } else if (newTransformer) {
setNewTransformer({ ...newTransformer, options: newOptions }); setNewTransformer({ ...newTransformer, parameters: newParameters });
} }
} }
}} }}
@@ -179,7 +179,7 @@ export function Transformers() {
value={value} value={value}
onChange={(e) => { onChange={(e) => {
if (editingTransformerIndex !== null) { if (editingTransformerIndex !== null) {
handleTransformerChange(editingTransformerIndex, "options", e.target.value, key); handleTransformerChange(editingTransformerIndex, "parameters", e.target.value, key);
} }
}} }}
className="flex-1" className="flex-1"
@@ -189,15 +189,15 @@ export function Transformers() {
size="icon" size="icon"
onClick={() => { onClick={() => {
if (editingTransformerIndex !== null) { if (editingTransformerIndex !== null) {
const options = editingTransformer.options || {}; const parameters = editingTransformer.parameters || {};
const newOptions = { ...options }; const newParameters = { ...parameters };
delete newOptions[key]; delete newParameters[key];
if (editingTransformerIndex < validTransformers.length) { if (editingTransformerIndex < validTransformers.length) {
const newTransformers = [...validTransformers]; const newTransformers = [...validTransformers];
newTransformers[editingTransformerIndex].options = newOptions; newTransformers[editingTransformerIndex].parameters = newParameters;
setConfig({ ...config, transformers: newTransformers }); setConfig({ ...config, Transformers: newTransformers });
} else if (newTransformer) { } else if (newTransformer) {
setNewTransformer({ ...newTransformer, options: newOptions }); setNewTransformer({ ...newTransformer, parameters: newParameters });
} }
} }
}} }}

View File

@@ -1,4 +1,4 @@
import type { Config, Provider, Transformer } from '@/components/ConfigProvider'; import type { Config, Provider, Transformer } from '@/types';
// API Client Class for handling requests with baseUrl and apikey authentication // API Client Class for handling requests with baseUrl and apikey authentication
class ApiClient { class ApiClient {

View File

@@ -77,7 +77,11 @@
"add_parameter": "Add Parameter", "add_parameter": "Add Parameter",
"parameter_name": "Parameter Name", "parameter_name": "Parameter Name",
"parameter_value": "Parameter Value", "parameter_value": "Parameter Value",
"selected_transformers": "Selected Transformers" "selected_transformers": "Selected Transformers",
"import_from_template": "Import from template",
"no_templates_found": "No templates found",
"select_template": "Select a template..."
}, },
"router": { "router": {
"title": "Router", "title": "Router",

View File

@@ -77,7 +77,11 @@
"add_parameter": "添加参数", "add_parameter": "添加参数",
"parameter_name": "参数名称", "parameter_name": "参数名称",
"parameter_value": "参数值", "parameter_value": "参数值",
"selected_transformers": "已选转换器" "selected_transformers": "已选转换器",
"import_from_template": "从模板导入",
"no_templates_found": "未找到模板",
"select_template": "选择一个模板..."
}, },
"router": { "router": {
"title": "路由", "title": "路由",

43
ui/src/types.ts Normal file
View File

@@ -0,0 +1,43 @@
export interface ProviderTransformer {
use: (string | (string | Record<string, unknown> | { max_tokens: number })[])[];
[key: string]: any; // Allow for model-specific transformers
}
export interface Provider {
name: string;
api_base_url: string;
api_key: string;
models: string[];
transformer?: ProviderTransformer;
}
export interface RouterConfig {
default: string;
background: string;
think: string;
longContext: string;
longContextThreshold: number;
webSearch: string;
custom?: any;
}
export interface Transformer {
name: string;
path: string;
project: string;
parameters?: Record<string, any>;
}
export interface Config {
Providers: Provider[];
Router: RouterConfig;
Transformers: Transformer[];
// Top-level settings
LOG: boolean;
CLAUDE_PATH: string;
HOST: string;
PORT: number;
APIKEY: string;
API_TIMEOUT_MS: string;
PROXY_URL: string;
}

View File

@@ -1 +1 @@
{"root":["./src/app.tsx","./src/i18n.ts","./src/main.tsx","./src/routes.tsx","./src/vite-env.d.ts","./src/components/configprovider.tsx","./src/components/jsoneditor.tsx","./src/components/login.tsx","./src/components/protectedroute.tsx","./src/components/providerlist.tsx","./src/components/providers.tsx","./src/components/publicroute.tsx","./src/components/router.tsx","./src/components/settingsdialog.tsx","./src/components/transformerlist.tsx","./src/components/transformers.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/combo-input.tsx","./src/components/ui/combobox.tsx","./src/components/ui/command.tsx","./src/components/ui/dialog.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/multi-combobox.tsx","./src/components/ui/popover.tsx","./src/components/ui/switch.tsx","./src/components/ui/toast.tsx","./src/lib/api.ts","./src/lib/utils.ts"],"version":"5.8.3"} {"root":["./src/app.tsx","./src/i18n.ts","./src/main.tsx","./src/routes.tsx","./src/types.ts","./src/vite-env.d.ts","./src/components/configprovider.tsx","./src/components/jsoneditor.tsx","./src/components/login.tsx","./src/components/protectedroute.tsx","./src/components/providerlist.tsx","./src/components/providers.tsx","./src/components/publicroute.tsx","./src/components/router.tsx","./src/components/settingsdialog.tsx","./src/components/transformerlist.tsx","./src/components/transformers.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/combo-input.tsx","./src/components/ui/combobox.tsx","./src/components/ui/command.tsx","./src/components/ui/dialog.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/multi-combobox.tsx","./src/components/ui/popover.tsx","./src/components/ui/switch.tsx","./src/components/ui/toast.tsx","./src/lib/api.ts","./src/lib/utils.ts"],"version":"5.8.3"}