Skip to content

Commit

Permalink
add import connection string
Browse files Browse the repository at this point in the history
  • Loading branch information
invisal committed Nov 27, 2024
1 parent 8f2286c commit 5befc21
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 10 deletions.
7 changes: 5 additions & 2 deletions src/database/editor-route.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Toolbar, ToolbarBackButton, ToolbarTitle } from "@/components/toolbar";
import ConnectionEditor from "./editor";
import { useNavigate, useParams } from "react-router-dom";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import {
ConnectionStoreItem,
ConnectionStoreManager,
Expand All @@ -14,8 +14,11 @@ export function ConnectionCreateUpdateRoute() {
connectionId?: string;
}>();

const { state: locationState } = useLocation();

const navigate = useNavigate();
const template = connectionTypeTemplates[type as string];

const [value, setValue] = useState<ConnectionStoreItem>(() => {
if (connectionId) {
const connectionValue = ConnectionStoreManager.get(connectionId);
Expand All @@ -26,7 +29,7 @@ export function ConnectionCreateUpdateRoute() {
id: crypto.randomUUID(),
name: "Unnamed Connection",
type: type!,
config: structuredClone(template.defaultValue),
config: structuredClone({ ...template.defaultValue, ...locationState }),
};
});

Expand Down
85 changes: 85 additions & 0 deletions src/database/import-connection-string.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Toolbar, ToolbarBackButton, ToolbarTitle } from "@/components/toolbar";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { useToast } from "@/hooks/use-toast";
import { ConnectionStoreItemConfig } from "@/lib/conn-manager-store";
import { useCallback, useState } from "react";
import { useNavigate } from "react-router-dom";

export default function ImportConnectionStringRoute() {
const { toast } = useToast();
const navigate = useNavigate();
const [connectionString, setConnectionString] = useState("");

const onImportClick = useCallback(() => {
let url = new URL(connectionString);
const protocol = url.protocol.replace(":", "");
const supportedProtocols = ["mysql", "postgresql"];

if (!supportedProtocols.includes(protocol)) {
toast({
title: "Import Failed",
description: "Invalid connection string",
});

return;
}

// Replace the connection string protocol with http for better parsing
url = new URL(connectionString.replace(`${protocol}:`, "http:"));

if (protocol === "mysql") {
console.log("Importing MySQL connection string");
navigate("/connection/create/mysql", {
replace: true,
state: {
host: url.hostname,
port: url.port ?? 3306,
username: url.username,
password: url.password,
database: url.pathname.replace("/", ""),
ssl: !!url.searchParams.get("ssl-mode"),
} as ConnectionStoreItemConfig,
});
return;
} else if (protocol === "postgresql") {
console.log("Importing Postgres connection string");
navigate("/connection/create/postgres", {
replace: true,
state: {
host: url.hostname,
port: url.port ?? 5432,
username: url.username,
password: url.password,
database: url.pathname.replace("/", ""),
ssl: !!url.searchParams.get("sslmode"),
} as ConnectionStoreItemConfig,
});
}
}, [connectionString, navigate, toast]);

return (
<div>
<Toolbar>
<ToolbarBackButton />
<ToolbarTitle text="Import from Connection String" />
</Toolbar>

<div className="flex flex-col gap-4 p-4">
<Textarea
rows={5}
className="resize-none p-4 font-mono"
placeholder="Connection String. Eg: mysql://root:123456@localhost:3306/database_name"
value={connectionString}
onChange={(e) => {
setConnectionString(e.currentTarget.value);
}}
/>

<div>
<Button onClick={onImportClick}>Import</Button>
</div>
</div>
</div>
);
}
13 changes: 13 additions & 0 deletions src/database/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
import { AnimatePresence, motion } from "framer-motion";
import { useToast } from "@/hooks/use-toast";
import { cn } from "@/lib/utils";
import ImportConnectionStringRoute from "./import-connection-string";

const connectionTypeList = [
"mysql",
Expand Down Expand Up @@ -270,6 +271,17 @@ function ConnectionListRoute() {
<div className="flex h-full w-full flex-col">
<Toolbar>
<ToolbarDropdown text="Add Connection" icon={LucidePlus}>
<DropdownMenuItem
onClick={() => {
navigate("/connection/import");
}}
>
<LucidePlus className="h-4 w-4" />
Import Connection String
</DropdownMenuItem>

<DropdownMenuSeparator />

{connectionTypeList.map((type) => {
const config = connectionTypeTemplates[type];
const IconComponent = config?.icon ?? MySQLIcon;
Expand Down Expand Up @@ -335,6 +347,7 @@ function ConnectionListRoute() {

const ROUTE_LIST = [
{ path: "/connection", Component: ConnectionListRoute },
{ path: "/connection/import", Component: ImportConnectionStringRoute },
{ path: "/connection/create/:type", Component: ConnectionCreateUpdateRoute },
{
path: "/connection/edit/:type/:connectionId",
Expand Down
17 changes: 9 additions & 8 deletions src/lib/conn-manager-store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ import {
TursoIcon,
} from "./outerbase-icon";

export interface ConnectionStoreItemConfig {
ssl?: boolean;
host: string;
port?: string;
database?: string;
username?: string;
password?: string;
}
export interface ConnectionStoreItem {
id: string;
name: string;
type: string;
config: {
ssl?: boolean;
host: string;
port?: string;
database?: string;
username?: string;
password?: string;
};
config: ConnectionStoreItemConfig;
}

interface ConnectionTypeTemplate {
Expand Down

0 comments on commit 5befc21

Please sign in to comment.