diff --git a/web/components/Navbar/index.tsx b/web/components/Navbar/index.tsx index 10a09325..e6dba6e9 100644 --- a/web/components/Navbar/index.tsx +++ b/web/components/Navbar/index.tsx @@ -1,6 +1,7 @@ import DocsLink from "@components/links/DocsLink"; import ExternalLink from "@components/links/ExternalLink"; import Link from "@components/links/Link"; +import { dockerHubRepo, workbenchGithubRepo } from "@lib/constants"; import { FaDocker } from "@react-icons/all-files/fa/FaDocker"; import { FaGithub } from "@react-icons/all-files/fa/FaGithub"; import css from "./index.module.css"; @@ -24,16 +25,10 @@ export default function Navbar() { <div className={css.right}> <div className={css.hubLinks}> - <ExternalLink - href="https://github.com/dolthub/dolt-workbench" - className={css.link} - > + <ExternalLink href={workbenchGithubRepo} className={css.link}> <FaGithub /> GitHub </ExternalLink> - <ExternalLink - href="https://hub.docker.com/r/dolthub/dolt-workbench" - className={css.link} - > + <ExternalLink href={dockerHubRepo} className={css.link}> <FaDocker /> Docker Hub </ExternalLink> </div> diff --git a/web/components/layouts/MainLayout/index.module.css b/web/components/layouts/MainLayout/index.module.css index 68d1026c..babfb07e 100644 --- a/web/components/layouts/MainLayout/index.module.css +++ b/web/components/layouts/MainLayout/index.module.css @@ -3,12 +3,12 @@ min-height: 100vh; footer { - @apply absolute bottom-0 w-full h-8 flex justify-end px-3; + @apply w-full h-8 flex justify-end px-4; } } .container { - @apply max-w-2xl py-40 px-4 mx-auto; + @apply max-w-2xl py-40 px-4 mx-auto min-h-[calc(100vh-5rem)]; h1 { @apply mb-6 text-center; diff --git a/web/components/pageComponents/ConnectionsPage/ExistingConnections/index.module.css b/web/components/pageComponents/ConnectionsPage/ExistingConnections/index.module.css index bf07c2d3..1ec8f96e 100644 --- a/web/components/pageComponents/ConnectionsPage/ExistingConnections/index.module.css +++ b/web/components/pageComponents/ConnectionsPage/ExistingConnections/index.module.css @@ -17,3 +17,11 @@ .err { @apply text-center; } + +.newConnection { + @apply flex items-center px-4; + + svg { + @apply mr-2; + } +} diff --git a/web/components/pageComponents/ConnectionsPage/ExistingConnections/index.tsx b/web/components/pageComponents/ConnectionsPage/ExistingConnections/index.tsx index b459f512..c8796398 100644 --- a/web/components/pageComponents/ConnectionsPage/ExistingConnections/index.tsx +++ b/web/components/pageComponents/ConnectionsPage/ExistingConnections/index.tsx @@ -5,6 +5,7 @@ import { StoredConnectionsDocument, useRemoveConnectionMutation, } from "@gen/graphql-types"; +import { AiOutlinePlus } from "@react-icons/all-files/ai/AiOutlinePlus"; import { useState } from "react"; import Item from "./Item"; import css from "./index.module.css"; @@ -52,8 +53,11 @@ export default function ExistingConnections(props: Props) { " connection? </p> </DeleteModal> - <Button onClick={() => props.setShowForm(true)}> - Add new connection + <Button + onClick={() => props.setShowForm(true)} + className={css.newConnection} + > + <AiOutlinePlus /> New connection </Button> </div> </div> diff --git a/web/components/pageComponents/ConnectionsPage/NewConnection/index.module.css b/web/components/pageComponents/ConnectionsPage/NewConnection/index.module.css index 9192b7fa..d103aed4 100644 --- a/web/components/pageComponents/ConnectionsPage/NewConnection/index.module.css +++ b/web/components/pageComponents/ConnectionsPage/NewConnection/index.module.css @@ -2,16 +2,20 @@ @apply w-full max-w-xl; h3 { - @apply mb-8; + @apply mb-4; } } .whiteContainer { - @apply max-w-xl w-full border rounded-lg py-10 px-16 bg-white mx-auto; + @apply max-w-xl w-full border rounded-lg py-10 bg-white mx-auto; } -.nameInput { - @apply pb-4 mb-8 border-b; +.section { + @apply px-14 py-4; +} + +.middle { + @apply border-y pt-8; } .or { @@ -29,3 +33,7 @@ .checkbox { @apply mt-7 mb-10 text-sm; } + +.instructions { + @apply mb-8; +} diff --git a/web/components/pageComponents/ConnectionsPage/NewConnection/index.tsx b/web/components/pageComponents/ConnectionsPage/NewConnection/index.tsx index 46e0ec3f..e2a2e9bd 100644 --- a/web/components/pageComponents/ConnectionsPage/NewConnection/index.tsx +++ b/web/components/pageComponents/ConnectionsPage/NewConnection/index.tsx @@ -3,8 +3,12 @@ import ButtonsWithError from "@components/ButtonsWithError"; import CustomCheckbox from "@components/CustomCheckbox"; import FormInput from "@components/FormInput"; import Loader from "@components/Loader"; +import ExternalLink from "@components/links/ExternalLink"; +import { dockerHubRepo } from "@lib/constants"; import { FaCaretDown } from "@react-icons/all-files/fa/FaCaretDown"; import { FaCaretUp } from "@react-icons/all-files/fa/FaCaretUp"; +import cx from "classnames"; +import { useEffect, useState } from "react"; import css from "./index.module.css"; import useConfig from "./useConfig"; @@ -17,6 +21,11 @@ export default function NewConnection(props: Props) { const { onSubmit, state, setState, error, clearState } = useConfig(); const canSubmit = state.name && (state.connectionUrl || (state.host && state.username)); + const [isDocker, setIsDocker] = useState(false); + + useEffect(() => { + setIsDocker(window.location.origin === "http://localhost:3000"); + }, []); const onCancel = props.canGoBack ? () => { @@ -29,100 +38,117 @@ export default function NewConnection(props: Props) { <Loader loaded={!state.loading} /> <div className={css.whiteContainer}> <form onSubmit={onSubmit}> - <h3>Set up new connection</h3> - <div className={css.nameInput}> + <div className={css.section}> + <h3>Set up new connection</h3> + <p className={css.instructions}> + View instructions for connecting to local and Docker installed + databases <ExternalLink href={dockerHubRepo}>here</ExternalLink>. + </p> + <div className={css.nameInput}> + <FormInput + value={state.name} + onChangeString={n => setState({ name: n })} + label="Name" + placeholder="my-database (required)" + horizontal + light + /> + </div> + </div> + <div className={cx(css.section, css.middle)}> + <FormInput + value={state.connectionUrl} + onChangeString={c => setState({ connectionUrl: c })} + label="URL" + placeholder="mysql://[user]:[password]@[host]/[database]" + horizontal + light + /> + <div className={css.or}>OR</div> + <FormInput + label="Host" + value={state.host} + onChangeString={h => setState({ host: h })} + placeholder={isDocker ? "host.docker.internal" : "127.0.0.1"} + horizontal + light + /> <FormInput - value={state.name} - onChangeString={n => setState({ name: n })} - label="Name" - placeholder="mydatabase (required)" + label="Port" + value={state.port} + onChangeString={p => setState({ port: p })} + placeholder="3306" horizontal + light + /> + <FormInput + label="User" + value={state.username} + onChangeString={u => setState({ username: u })} + placeholder="root" + horizontal + light + /> + <FormInput + label="Password" + value={state.password} + onChangeString={p => setState({ password: p })} + placeholder="**********" + type="password" + horizontal + light + /> + <FormInput + label="Database" + value={state.database} + onChangeString={d => setState({ database: d })} + placeholder="mydb" + horizontal + light /> </div> - <FormInput - value={state.connectionUrl} - onChangeString={c => setState({ connectionUrl: c })} - label="URL" - placeholder="mysql://[username]:[password]@[host]/[database]" - horizontal - /> - <div className={css.or}>OR</div> - <FormInput - label="Host" - value={state.host} - onChangeString={h => setState({ host: h })} - placeholder="127.0.0.1" - horizontal - /> - <FormInput - label="Port" - value={state.port} - onChangeString={p => setState({ port: p })} - placeholder="3306" - horizontal - /> - <FormInput - label="Username" - value={state.username} - onChangeString={u => setState({ username: u })} - placeholder="root" - horizontal - /> - <FormInput - label="Password" - value={state.password} - onChangeString={p => setState({ password: p })} - placeholder="**********" - type="password" - horizontal - /> - <FormInput - label="Database" - value={state.database} - onChangeString={d => setState({ database: d })} - placeholder="mydb" - horizontal - /> - <Button.Link - onClick={() => - setState({ showAdvancedSettings: !state.showAdvancedSettings }) - } - className={css.advancedSettings} - > - {state.showAdvancedSettings ? <FaCaretUp /> : <FaCaretDown />}{" "} - Advanced settings - </Button.Link> - {state.showAdvancedSettings && ( - <div> - <CustomCheckbox - checked={state.useSSL} - onChange={() => setState({ useSSL: !state.useSSL })} - name="use-ssl" - label="Use SSL" - description="If server does not allow insecure connections, client must use SSL/TLS." - className={css.checkbox} - /> - <CustomCheckbox - checked={state.hideDoltFeatures} - onChange={() => - setState({ hideDoltFeatures: !state.hideDoltFeatures }) - } - name="hide-dolt-features" - label="Hide Dolt features" - description="Hides Dolt features like branches, logs, and commits for non-Dolt MySQL databases. Will otherwise be disabled." - className={css.checkbox} - /> - </div> - )} - <ButtonsWithError - error={error} - onCancel={onCancel} - cancelText={props.canGoBack ? "cancel" : "clear"} - > - <Button type="submit" disabled={!canSubmit}> - Launch Workbench - </Button> - </ButtonsWithError> + <div className={css.section}> + <Button.Link + onClick={() => + setState({ showAdvancedSettings: !state.showAdvancedSettings }) + } + className={css.advancedSettings} + > + {state.showAdvancedSettings ? <FaCaretUp /> : <FaCaretDown />}{" "} + Advanced settings + </Button.Link> + {state.showAdvancedSettings && ( + <div> + <CustomCheckbox + checked={state.useSSL} + onChange={() => setState({ useSSL: !state.useSSL })} + name="use-ssl" + label="Use SSL" + description="If server does not allow insecure connections, client must use SSL/TLS." + className={css.checkbox} + /> + <CustomCheckbox + checked={state.hideDoltFeatures} + onChange={() => + setState({ hideDoltFeatures: !state.hideDoltFeatures }) + } + name="hide-dolt-features" + label="Hide Dolt features" + description="Hides Dolt features like branches, logs, and commits for non-Dolt MySQL databases. Will otherwise be disabled." + className={css.checkbox} + /> + </div> + )} + <ButtonsWithError + error={error} + onCancel={onCancel} + cancelText={props.canGoBack ? "cancel" : "clear"} + > + <Button type="submit" disabled={!canSubmit}> + Launch Workbench + </Button> + </ButtonsWithError> + </div> </form> </div> </div> diff --git a/web/lib/constants.ts b/web/lib/constants.ts index 2e2f7537..515a2f0e 100644 --- a/web/lib/constants.ts +++ b/web/lib/constants.ts @@ -1,3 +1,5 @@ export const discordLink = "https://discord.gg/gqr7K4VNKe"; export const docsLink = "https://docs.dolthub.com"; export const doltGithubRepo = "https://github.com/dolthub/dolt"; +export const workbenchGithubRepo = "https://github.com/dolthub/dolt-workbench"; +export const dockerHubRepo = "https://hub.docker.com/r/dolthub/dolt-workbench"; diff --git a/web/lib/errors/helpers.ts b/web/lib/errors/helpers.ts index 0e4150c8..d46476f1 100644 --- a/web/lib/errors/helpers.ts +++ b/web/lib/errors/helpers.ts @@ -31,6 +31,8 @@ export function improveErrorMsg(message: string): string { switch (message) { case "": return "Error message empty"; + case "Server does not support secure connnection": + return "Server does not support secure connection. See advanced settings to disable SSL."; default: return message; }