import { useCallback, useEffect, useState } from "react";
import { IConnectionOptions, IEditConnection } from "@components/Library/types";
import { ArrowPathIcon, XMarkIcon } from "@heroicons/react/24/outline";
import { getRouteApi, useNavigate } from "@tanstack/react-router";
import { AlertIcon, AlertModal } from "@components/Library/AlertModal";
import { enqueueSnackbar } from "notistack";
import {
useDeleteConnection,
useGetConnection,
useGetConversations,
useUpdateConnection,
useRefreshConnectionSchema,
} from "@/hooks";
import { Button } from "../Catalyst/button";
import { Transition } from "@headlessui/react";
import { ChevronDownIcon } from "@heroicons/react/20/solid";
import { Switch } from "@components/Catalyst/switch";
function classNames(...classes: string[]) {
return classes.filter(Boolean).join(" ");
}
const SchemaEditor = ({
options,
setOptions,
}: {
options: IConnectionOptions;
setOptions: (newOptions: IConnectionOptions) => void;
}) => {
const [expanded, setExpanded] = useState(
Object.fromEntries(options.schemas.map((schema) => [schema.name, false]))
);
return (
{options.schemas.map((schema, schema_index) =>
schema.tables.length === 0 ? null : (
// Check/Uncheck schema and its tables
setOptions({
schemas: options.schemas.map((prev_schema, prev_idx) =>
prev_idx === schema_index
? {
...prev_schema,
enabled: checked,
tables: prev_schema.tables.map((table) => ({
...table,
enabled: checked,
})),
}
: prev_schema
),
})
}
/>
setExpanded((prev) => ({
...prev,
[schema.name]: !prev[schema.name],
}))
}
>
{schema.name}
{schema.tables.map((table, table_index) => (
// Check/Uncheck table
setOptions({
schemas: options.schemas.map(
(prev_schema, prev_idx) =>
prev_idx === schema_index
? {
...prev_schema,
tables: prev_schema.tables.map(
(table, inner_table_idx) =>
inner_table_idx === table_index
? {
...table,
enabled: checked,
}
: table
),
}
: prev_schema
),
})
}
/>
{table.name}
))}
)
)}
);
};
const connectionRouteApi = getRouteApi("/_app/connection/$connectionId");
export const ConnectionEditor = () => {
const navigate = useNavigate();
const { connectionId } = connectionRouteApi.useParams();
const [unsavedChanges, setUnsavedChanges] = useState(false);
const [showCancelAlert, setShowCancelAlert] = useState(false);
const [showDeleteAlert, setShowDeleteAlert] = useState(false);
const { data, isLoading } = useGetConnection(connectionId);
const { data: conversationsData } = useGetConversations();
const relatedConversations =
conversationsData?.filter(
(conversation) => conversation.connection_id === connectionId
) ?? [];
const connection = data;
const { mutate: deleteConnection } = useDeleteConnection({
onSuccess() {
navigate({ to: "/" });
},
});
const { mutate: updateConnection } = useUpdateConnection({
onSuccess() {
navigate({ to: "/" });
},
});
const { mutate: refreshSchema, isPending: isRefreshing } =
useRefreshConnectionSchema((data) => {
setEditFields((prev) => ({
...prev,
options: data.options,
}));
});
// Form state
const [editFields, setEditFields] = useState({
name: "",
dsn: "",
});
useEffect(() => {
setEditFields((prev) => ({
name: connection?.name || prev.name,
dsn: connection?.dsn || prev.dsn,
options: connection?.options || prev.options,
}));
}, [connection]);
if (!connectionId) {
enqueueSnackbar({
variant: "error",
message: "No connection id provided - something went wrong",
});
}
// Handle navigating back only if there are no unsaved changes
const handleBack = useCallback(() => {
if (unsavedChanges) {
setShowCancelAlert(true);
} else {
navigate({ to: "/" });
}
}, [navigate, unsavedChanges]);
// Handle navigating back when escape is pressed
useEffect(() => {
const handleKeyPress = (event: { key: string }) => {
if (event.key === "Escape") {
handleBack();
}
};
// Add an event listener for the "Escape" key press
document.addEventListener("keydown", handleKeyPress);
// Clean up the event listener when the component unmounts
return () => {
document.removeEventListener("keydown", handleKeyPress);
};
}, [handleBack, unsavedChanges]);
function handleDelete() {
if (!connectionId) return;
deleteConnection(connectionId);
}
function handleSubmit() {
if (!unsavedChanges) {
navigate({ to: "/" }); // Return to previous page
return;
}
if (!connectionId) return;
updateConnection({
id: connectionId,
payload: {
name: editFields.name,
...(editFields.dsn !== connection?.dsn && { dsn: editFields.dsn }), // only add dsn if it changed
options: editFields.options,
},
});
}
return (
{
setShowCancelAlert(false);
history.back();
}}
onCancel={() => {
setShowCancelAlert(false);
}}
/>
{
setShowDeleteAlert(false);
handleDelete();
}}
onCancel={() => {
setShowDeleteAlert(false);
}}
/>
{editFields.options && (
{
setEditFields((prev) => ({
...prev,
options: newOptions,
}));
setUnsavedChanges(true);
}}
/>
)}
);
};