-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: handle invalid connection error (#5)
* transform libsql:// to wss:// * add schema provider * feat: handle error message when connecting to server * fix: fixing the refresh * make the story use client * fixing sonarqube issue
- Loading branch information
Showing
10 changed files
with
214 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
"use client"; | ||
import ConnectingDialog from "@/screens/DatabaseScreen/ConnectingDialog"; | ||
|
||
export default function ConnectionErrorMessageStory() { | ||
return ( | ||
<div className="flex flex-col gap-4"> | ||
<ConnectingDialog message="Authentication failed: The JWT is invalid" /> | ||
<ConnectingDialog loading url="wss://example.turso.io" /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export default function ErrorMessage({ | ||
message, | ||
}: { | ||
readonly message: string; | ||
}) { | ||
return <div className="text-xs text-red-500">{message}</div>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { Button } from "@/components/ui/button"; | ||
import { LucideLoader } from "lucide-react"; | ||
import { useRouter } from "next/navigation"; | ||
|
||
export default function ConnectingDialog({ | ||
message, | ||
url, | ||
onRetry, | ||
}: Readonly<{ | ||
loading?: boolean; | ||
url?: string; | ||
message?: string; | ||
onRetry?: () => void; | ||
}>) { | ||
const router = useRouter(); | ||
|
||
let body = ( | ||
<div> | ||
<p className="mt-4 flex gap-4"> | ||
<LucideLoader className="animate-spin" /> | ||
Connecting to <strong>{url}</strong> | ||
</p> | ||
</div> | ||
); | ||
|
||
if (message) { | ||
body = ( | ||
<> | ||
<div className="text-2xl font-semibold"> | ||
We have problem connecting to database | ||
</div> | ||
<p className="mt-4"> | ||
<pre>{message}</pre> | ||
</p> | ||
<div className="mt-4 flex gap-4"> | ||
<Button onClick={onRetry}>Retry</Button> | ||
<Button variant={"secondary"} onClick={() => router.push("/")}> | ||
Back | ||
</Button> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
return ( | ||
<div className="p-8"> | ||
<div | ||
className="mb-4 flex gap-2 items-center pl-8 pt-4 pb-4 rounded-lg select-none text-white" | ||
style={{ background: "#2C5FC3", maxWidth: 300 }} | ||
> | ||
<img src="/libsql-logo.png" alt="LibSQL Studio" className="w-12 h-12" /> | ||
<div> | ||
<h1 className="text-2xl font-semibold">LibSQL Studio</h1> | ||
</div> | ||
</div> | ||
|
||
{body} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { useAutoComplete } from "@/context/AutoCompleteProvider"; | ||
import { useDatabaseDriver } from "@/context/DatabaseDriverProvider"; | ||
import { DatabaseSchemaItem } from "@/drivers/DatabaseDriver"; | ||
import { | ||
PropsWithChildren, | ||
createContext, | ||
useCallback, | ||
useContext, | ||
useEffect, | ||
useMemo, | ||
useState, | ||
} from "react"; | ||
import ConnectingDialog from "./ConnectingDialog"; | ||
|
||
const SchemaContext = createContext<{ | ||
schema: DatabaseSchemaItem[]; | ||
refresh: () => void; | ||
}>({ | ||
schema: [], | ||
refresh: () => { | ||
throw new Error("Not implemented"); | ||
}, | ||
}); | ||
|
||
export function useSchema() { | ||
return useContext(SchemaContext); | ||
} | ||
|
||
export function SchemaProvider({ children }: Readonly<PropsWithChildren>) { | ||
const { updateTableList } = useAutoComplete(); | ||
const [error, setError] = useState<string>(); | ||
const [schemaItems, setSchemaItems] = useState<DatabaseSchemaItem[]>([]); | ||
const [loading, setLoading] = useState(true); | ||
const { databaseDriver } = useDatabaseDriver(); | ||
|
||
const fetchSchema = useCallback( | ||
(refresh?: boolean) => { | ||
if (refresh) { | ||
setLoading(true); | ||
} | ||
|
||
databaseDriver | ||
.getTableList() | ||
.then((tableList) => { | ||
const sortedTableList = [...tableList]; | ||
sortedTableList.sort((a, b) => { | ||
return a.name.localeCompare(b.name); | ||
}); | ||
|
||
setSchemaItems(sortedTableList); | ||
updateTableList(tableList.map((table) => table.name)); | ||
|
||
setError(undefined); | ||
setLoading(false); | ||
}) | ||
.catch((e) => { | ||
setError(e.message); | ||
setLoading(false); | ||
}); | ||
}, | ||
[databaseDriver, updateTableList, setError] | ||
); | ||
|
||
useEffect(() => { | ||
fetchSchema(true); | ||
}, [fetchSchema]); | ||
|
||
const props = useMemo(() => { | ||
return { schema: schemaItems, refresh: fetchSchema }; | ||
}, [schemaItems, fetchSchema]); | ||
|
||
if (error || loading) { | ||
return ( | ||
<ConnectingDialog | ||
message={error} | ||
loading={loading} | ||
url={databaseDriver.getEndpoint()} | ||
/> | ||
); | ||
} | ||
|
||
return ( | ||
<SchemaContext.Provider value={props}>{children}</SchemaContext.Provider> | ||
); | ||
} |