refactor: improve code formatting and readability across multiple files
This commit is contained in:
parent
c5acc63129
commit
cb8c45456b
6 changed files with 79 additions and 42 deletions
|
|
@ -74,7 +74,10 @@ import ElicitationTab, {
|
||||||
PendingElicitationRequest,
|
PendingElicitationRequest,
|
||||||
ElicitationResponse,
|
ElicitationResponse,
|
||||||
} from "./components/ElicitationTab";
|
} from "./components/ElicitationTab";
|
||||||
import { CustomHeaders, migrateFromLegacyAuth } from "./lib/types/customHeaders";
|
import {
|
||||||
|
CustomHeaders,
|
||||||
|
migrateFromLegacyAuth,
|
||||||
|
} from "./lib/types/customHeaders";
|
||||||
|
|
||||||
const CONFIG_LOCAL_STORAGE_KEY = "inspectorConfig_v1";
|
const CONFIG_LOCAL_STORAGE_KEY = "inspectorConfig_v1";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { Plus, Trash2, Eye, EyeOff } from "lucide-react";
|
import { Plus, Trash2, Eye, EyeOff } from "lucide-react";
|
||||||
import { CustomHeaders as CustomHeadersType, CustomHeader, createEmptyHeader } from "@/lib/types/customHeaders";
|
import {
|
||||||
|
CustomHeaders as CustomHeadersType,
|
||||||
|
CustomHeader,
|
||||||
|
createEmptyHeader,
|
||||||
|
} from "@/lib/types/customHeaders";
|
||||||
|
|
||||||
interface CustomHeadersProps {
|
interface CustomHeadersProps {
|
||||||
headers: CustomHeadersType;
|
headers: CustomHeadersType;
|
||||||
|
|
@ -12,13 +16,21 @@ interface CustomHeadersProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CustomHeaders = ({ headers, onChange, className }: CustomHeadersProps) => {
|
const CustomHeaders = ({
|
||||||
|
headers,
|
||||||
|
onChange,
|
||||||
|
className,
|
||||||
|
}: CustomHeadersProps) => {
|
||||||
const [isJsonMode, setIsJsonMode] = useState(false);
|
const [isJsonMode, setIsJsonMode] = useState(false);
|
||||||
const [jsonValue, setJsonValue] = useState("");
|
const [jsonValue, setJsonValue] = useState("");
|
||||||
const [jsonError, setJsonError] = useState<string | null>(null);
|
const [jsonError, setJsonError] = useState<string | null>(null);
|
||||||
const [visibleValues, setVisibleValues] = useState<Set<number>>(new Set());
|
const [visibleValues, setVisibleValues] = useState<Set<number>>(new Set());
|
||||||
|
|
||||||
const updateHeader = (index: number, field: keyof CustomHeader, value: string | boolean) => {
|
const updateHeader = (
|
||||||
|
index: number,
|
||||||
|
field: keyof CustomHeader,
|
||||||
|
value: string | boolean,
|
||||||
|
) => {
|
||||||
const newHeaders = [...headers];
|
const newHeaders = [...headers];
|
||||||
newHeaders[index] = { ...newHeaders[index], [field]: value };
|
newHeaders[index] = { ...newHeaders[index], [field]: value };
|
||||||
onChange(newHeaders);
|
onChange(newHeaders);
|
||||||
|
|
@ -58,16 +70,22 @@ const CustomHeaders = ({ headers, onChange, className }: CustomHeadersProps) =>
|
||||||
const switchToFormMode = () => {
|
const switchToFormMode = () => {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(jsonValue);
|
const parsed = JSON.parse(jsonValue);
|
||||||
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
if (
|
||||||
|
typeof parsed !== "object" ||
|
||||||
|
parsed === null ||
|
||||||
|
Array.isArray(parsed)
|
||||||
|
) {
|
||||||
setJsonError("JSON must be an object with string key-value pairs");
|
setJsonError("JSON must be an object with string key-value pairs");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newHeaders: CustomHeadersType = Object.entries(parsed).map(([name, value]) => ({
|
const newHeaders: CustomHeadersType = Object.entries(parsed).map(
|
||||||
name,
|
([name, value]) => ({
|
||||||
value: String(value),
|
name,
|
||||||
enabled: true,
|
value: String(value),
|
||||||
}));
|
enabled: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
onChange(newHeaders);
|
onChange(newHeaders);
|
||||||
setJsonError(null);
|
setJsonError(null);
|
||||||
|
|
@ -86,7 +104,9 @@ const CustomHeaders = ({ headers, onChange, className }: CustomHeadersProps) =>
|
||||||
return (
|
return (
|
||||||
<div className={`space-y-3 ${className}`}>
|
<div className={`space-y-3 ${className}`}>
|
||||||
<div className="flex justify-between items-center gap-2">
|
<div className="flex justify-between items-center gap-2">
|
||||||
<h4 className="text-sm font-semibold flex-shrink-0">Custom Headers (JSON)</h4>
|
<h4 className="text-sm font-semibold flex-shrink-0">
|
||||||
|
Custom Headers (JSON)
|
||||||
|
</h4>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
|
|
@ -104,9 +124,7 @@ const CustomHeaders = ({ headers, onChange, className }: CustomHeadersProps) =>
|
||||||
placeholder='{\n "Authorization": "Bearer token123",\n "X-Tenant-ID": "acme-inc",\n "X-Environment": "staging"\n}'
|
placeholder='{\n "Authorization": "Bearer token123",\n "X-Tenant-ID": "acme-inc",\n "X-Environment": "staging"\n}'
|
||||||
className="font-mono text-sm min-h-[100px] resize-none"
|
className="font-mono text-sm min-h-[100px] resize-none"
|
||||||
/>
|
/>
|
||||||
{jsonError && (
|
{jsonError && <p className="text-sm text-red-600">{jsonError}</p>}
|
||||||
<p className="text-sm text-red-600">{jsonError}</p>
|
|
||||||
)}
|
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Enter headers as a JSON object with string key-value pairs.
|
Enter headers as a JSON object with string key-value pairs.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -156,7 +174,9 @@ const CustomHeaders = ({ headers, onChange, className }: CustomHeadersProps) =>
|
||||||
>
|
>
|
||||||
<Switch
|
<Switch
|
||||||
checked={header.enabled}
|
checked={header.enabled}
|
||||||
onCheckedChange={(enabled) => updateHeader(index, "enabled", enabled)}
|
onCheckedChange={(enabled) =>
|
||||||
|
updateHeader(index, "enabled", enabled)
|
||||||
|
}
|
||||||
className="shrink-0 mt-2"
|
className="shrink-0 mt-2"
|
||||||
/>
|
/>
|
||||||
<div className="flex-1 min-w-0 space-y-2">
|
<div className="flex-1 min-w-0 space-y-2">
|
||||||
|
|
@ -170,7 +190,9 @@ const CustomHeaders = ({ headers, onChange, className }: CustomHeadersProps) =>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Header Value"
|
placeholder="Header Value"
|
||||||
value={header.value}
|
value={header.value}
|
||||||
onChange={(e) => updateHeader(index, "value", e.target.value)}
|
onChange={(e) =>
|
||||||
|
updateHeader(index, "value", e.target.value)
|
||||||
|
}
|
||||||
type={visibleValues.has(index) ? "text" : "password"}
|
type={visibleValues.has(index) ? "text" : "password"}
|
||||||
className="font-mono text-xs pr-8"
|
className="font-mono text-xs pr-8"
|
||||||
/>
|
/>
|
||||||
|
|
@ -205,7 +227,8 @@ const CustomHeaders = ({ headers, onChange, className }: CustomHeadersProps) =>
|
||||||
|
|
||||||
{headers.length > 0 && (
|
{headers.length > 0 && (
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Use the toggle to enable/disable headers. Only enabled headers with both name and value will be sent.
|
Use the toggle to enable/disable headers. Only enabled headers with
|
||||||
|
both name and value will be sent.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ const Switch = React.forwardRef<
|
||||||
<SwitchPrimitives.Root
|
<SwitchPrimitives.Root
|
||||||
className={cn(
|
className={cn(
|
||||||
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
<SwitchPrimitives.Thumb
|
<SwitchPrimitives.Thumb
|
||||||
className={cn(
|
className={cn(
|
||||||
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</SwitchPrimitives.Root>
|
</SwitchPrimitives.Root>
|
||||||
|
|
|
||||||
|
|
@ -779,7 +779,10 @@ describe("useConnection", () => {
|
||||||
expect(headers).toHaveProperty("Authorization", "Bearer token123");
|
expect(headers).toHaveProperty("Authorization", "Bearer token123");
|
||||||
expect(headers).toHaveProperty("X-Tenant-ID", "acme-inc");
|
expect(headers).toHaveProperty("X-Tenant-ID", "acme-inc");
|
||||||
expect(headers).toHaveProperty("X-Environment", "staging");
|
expect(headers).toHaveProperty("X-Environment", "staging");
|
||||||
expect(headers).toHaveProperty("x-custom-auth-headers", JSON.stringify(["X-Tenant-ID", "X-Environment"]));
|
expect(headers).toHaveProperty(
|
||||||
|
"x-custom-auth-headers",
|
||||||
|
JSON.stringify(["X-Tenant-ID", "X-Environment"]),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ignores disabled custom headers", async () => {
|
test("ignores disabled custom headers", async () => {
|
||||||
|
|
@ -815,9 +818,7 @@ describe("useConnection", () => {
|
||||||
headerName: "X-Custom-Auth",
|
headerName: "X-Custom-Auth",
|
||||||
};
|
};
|
||||||
|
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() => useConnection(propsWithLegacyAuth));
|
||||||
useConnection(propsWithLegacyAuth),
|
|
||||||
);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await result.current.connect();
|
await result.current.connect();
|
||||||
|
|
@ -825,7 +826,10 @@ describe("useConnection", () => {
|
||||||
|
|
||||||
const headers = mockSSETransport.options?.requestInit?.headers;
|
const headers = mockSSETransport.options?.requestInit?.headers;
|
||||||
expect(headers).toHaveProperty("X-Custom-Auth", "legacy-token");
|
expect(headers).toHaveProperty("X-Custom-Auth", "legacy-token");
|
||||||
expect(headers).toHaveProperty("x-custom-auth-headers", JSON.stringify(["X-Custom-Auth"]));
|
expect(headers).toHaveProperty(
|
||||||
|
"x-custom-auth-headers",
|
||||||
|
JSON.stringify(["X-Custom-Auth"]),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("uses OAuth token when no custom headers or legacy auth provided", async () => {
|
test("uses OAuth token when no custom headers or legacy auth provided", async () => {
|
||||||
|
|
@ -833,9 +837,7 @@ describe("useConnection", () => {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() => useConnection(propsWithoutAuth));
|
||||||
useConnection(propsWithoutAuth),
|
|
||||||
);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await result.current.connect();
|
await result.current.connect();
|
||||||
|
|
@ -857,9 +859,7 @@ describe("useConnection", () => {
|
||||||
headerName: "Authorization",
|
headerName: "Authorization",
|
||||||
};
|
};
|
||||||
|
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() => useConnection(propsWithBothAuth));
|
||||||
useConnection(propsWithBothAuth),
|
|
||||||
);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await result.current.connect();
|
await result.current.connect();
|
||||||
|
|
|
||||||
|
|
@ -17,28 +17,35 @@ export const createHeaderFromBearerToken = (
|
||||||
headerName?: string,
|
headerName?: string,
|
||||||
): CustomHeader => ({
|
): CustomHeader => ({
|
||||||
name: headerName || "Authorization",
|
name: headerName || "Authorization",
|
||||||
value: headerName?.toLowerCase() === "authorization" || !headerName
|
value:
|
||||||
? `Bearer ${bearerToken}`
|
headerName?.toLowerCase() === "authorization" || !headerName
|
||||||
: bearerToken,
|
? `Bearer ${bearerToken}`
|
||||||
|
: bearerToken,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getEnabledHeaders = (headers: CustomHeaders): CustomHeaders => {
|
export const getEnabledHeaders = (headers: CustomHeaders): CustomHeaders => {
|
||||||
return headers.filter(header => header.enabled && header.name.trim() && header.value.trim());
|
return headers.filter(
|
||||||
|
(header) => header.enabled && header.name.trim() && header.value.trim(),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const headersToRecord = (headers: CustomHeaders): Record<string, string> => {
|
export const headersToRecord = (
|
||||||
|
headers: CustomHeaders,
|
||||||
|
): Record<string, string> => {
|
||||||
const enabledHeaders = getEnabledHeaders(headers);
|
const enabledHeaders = getEnabledHeaders(headers);
|
||||||
const record: Record<string, string> = {};
|
const record: Record<string, string> = {};
|
||||||
|
|
||||||
enabledHeaders.forEach(header => {
|
enabledHeaders.forEach((header) => {
|
||||||
record[header.name.trim()] = header.value.trim();
|
record[header.name.trim()] = header.value.trim();
|
||||||
});
|
});
|
||||||
|
|
||||||
return record;
|
return record;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const recordToHeaders = (record: Record<string, string>): CustomHeaders => {
|
export const recordToHeaders = (
|
||||||
|
record: Record<string, string>,
|
||||||
|
): CustomHeaders => {
|
||||||
return Object.entries(record).map(([name, value]) => ({
|
return Object.entries(record).map(([name, value]) => ({
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
|
|
@ -54,6 +61,6 @@ export const migrateFromLegacyAuth = (
|
||||||
if (!bearerToken) {
|
if (!bearerToken) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [createHeaderFromBearerToken(bearerToken, headerName)];
|
return [createHeaderFromBearerToken(bearerToken, headerName)];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -93,13 +93,17 @@ const getHttpHeaders = (req: express.Request): Record<string, string> => {
|
||||||
// Handle multiple custom headers (new approach)
|
// Handle multiple custom headers (new approach)
|
||||||
if (req.headers["x-custom-auth-headers"] !== undefined) {
|
if (req.headers["x-custom-auth-headers"] !== undefined) {
|
||||||
try {
|
try {
|
||||||
const customHeaderNames = JSON.parse(req.headers["x-custom-auth-headers"] as string) as string[];
|
const customHeaderNames = JSON.parse(
|
||||||
|
req.headers["x-custom-auth-headers"] as string,
|
||||||
|
) as string[];
|
||||||
if (Array.isArray(customHeaderNames)) {
|
if (Array.isArray(customHeaderNames)) {
|
||||||
customHeaderNames.forEach((headerName) => {
|
customHeaderNames.forEach((headerName) => {
|
||||||
const lowerCaseHeaderName = headerName.toLowerCase();
|
const lowerCaseHeaderName = headerName.toLowerCase();
|
||||||
if (req.headers[lowerCaseHeaderName] !== undefined) {
|
if (req.headers[lowerCaseHeaderName] !== undefined) {
|
||||||
const value = req.headers[lowerCaseHeaderName];
|
const value = req.headers[lowerCaseHeaderName];
|
||||||
headers[headerName] = Array.isArray(value) ? value[value.length - 1] : value;
|
headers[headerName] = Array.isArray(value)
|
||||||
|
? value[value.length - 1]
|
||||||
|
: value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue