Skip to content

Commit

Permalink
Merge pull request #985 from tailwarden/feature/tech-1645
Browse files Browse the repository at this point in the history
feat: allow user to configure a database
  • Loading branch information
mlabouardy authored Sep 27, 2023
2 parents 642cd33 + cf79e2f commit 791ef40
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 72 deletions.
24 changes: 24 additions & 0 deletions dashboard/components/icons/AlertCircleIconFilled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { SVGProps } from 'react';

const AlertCircleIconFilled = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 17 "
fill="none"
{...props}
>
<path
fill="currentColor"
d="M7.9997 15.3763c3.6819 0 6.6666-2.9848 6.6666-6.6667 0-3.6819-2.9847-6.6666-6.6666-6.6666-3.682 0-6.6667 2.9847-6.6667 6.6666 0 3.6819 2.9848 6.6667 6.6667 6.6667Z"
/>
<path
stroke="#fff"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 6.043v2.6666M8 11.3765h.0067"
/>
</svg>
);

export default AlertCircleIconFilled;
10 changes: 2 additions & 8 deletions dashboard/components/onboarding-wizard/CredentialsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,14 @@ function CredentialsButton({
return (
<div className="flex justify-between">
<Button
onClick={() => router.back()}
onClick={() => router.push('/onboarding/choose-database/')}
size="lg"
style="text"
type="button"
>
Back
</Button>
<Button
onClick={handleNext}
size="lg"
style="primary"
type="button"
disabled={true}
>
<Button onClick={handleNext} size="lg" style="primary" type="submit">
{nextLabel}
</Button>
</div>
Expand Down
20 changes: 20 additions & 0 deletions dashboard/components/onboarding-wizard/DatabaseErrorMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function DatabaseErrorMessage() {
return (
<div className="mt-8 rounded-md bg-error-100 px-3 py-1.5 text-sm text-error-600">
We&apos;re sorry, but we were unable to connect to your database using the
information provided. Please ensure that the information are correct and
try again. If you continue to experience issues, please{' '}
<a
href="https://discord.tailwarden.com"
target="_blank"
rel="noreferrer"
className="underline"
>
contact our support
</a>{' '}
team for assistance.
</div>
);
}

export default DatabaseErrorMessage;
27 changes: 23 additions & 4 deletions dashboard/components/onboarding-wizard/InputFileSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { MutableRefObject, ReactNode } from 'react';
import classNames from 'classnames';
import AlertCircleIcon from '../icons/AlertCircleIcon';
import AlertIcon from '../icons/AlertIcon';
import AlertCircleIconFilled from '../icons/AlertCircleIconFilled';

interface InputFileSelectProps {
id: string;
Expand All @@ -8,6 +12,8 @@ interface InputFileSelectProps {
icon?: ReactNode;
subLabel?: string;
disabled?: boolean;
hasError?: boolean;
errorMessage?: string;
placeholder?: string;
iconClick?: () => void;
handleFileChange: (event: any) => void;
Expand All @@ -25,10 +31,12 @@ function InputFileSelect({
placeholder,
fileInputRef,
handleFileChange,
disabled = false
disabled = false,
hasError = false,
errorMessage = ''
}: InputFileSelectProps) {
return (
<div>
<div className="relative mb-6">
<label htmlFor={id} className="mb-2 block text-gray-700">
{label}
</label>
Expand All @@ -39,7 +47,7 @@ function InputFileSelect({
</span>
)}

<div className="relative mb-6">
<div className="relative">
<input
type="file"
className="hidden"
Expand All @@ -53,7 +61,12 @@ function InputFileSelect({
value={value}
disabled={disabled}
placeholder={placeholder}
className="block w-full rounded border py-4 pl-5 text-sm text-black-900 outline outline-black-200 focus:outline-2 focus:outline-primary"
className={classNames(
hasError
? 'outline-error-600 focus:outline-error-700'
: 'outline-gray-200 focus:outline-primary',
'block w-full rounded border py-4 pl-5 text-sm text-black-900 outline focus:outline-2 '
)}
/>

{icon && (
Expand All @@ -65,6 +78,12 @@ function InputFileSelect({
</button>
)}
</div>
{hasError && errorMessage && (
<div className="mt-2 flex items-center text-sm text-error-600">
<AlertCircleIconFilled className="mr-1 inline-block h-4 w-4" />
{errorMessage}
</div>
)}
</div>
);
}
Expand Down
3 changes: 3 additions & 0 deletions dashboard/components/onboarding-wizard/LabelledInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface LabelledInputProps {
subLabel?: string;
disabled?: boolean;
placeholder?: string;
required?: boolean;
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
}

Expand All @@ -20,6 +21,7 @@ function LabelledInput({
value,
subLabel,
placeholder,
required = false,
disabled = false,
onChange
}: LabelledInputProps) {
Expand Down Expand Up @@ -48,6 +50,7 @@ function LabelledInput({
value={value}
disabled={disabled}
placeholder={placeholder}
required={required}
className={`block w-full rounded py-[14.5px] text-sm text-black-900 outline outline-black-200 focus:outline-2 focus:outline-primary ${
icon ? 'pl-10' : 'pl-3'
}`}
Expand Down
6 changes: 4 additions & 2 deletions dashboard/pages/onboarding/choose-database.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ function DatabaseLeftItem({
return (
<div
onClick={onClick}
className={`flex flex-col items-center justify-center rounded-lg border-[1.5px] p-6 ${
selected === value ? 'border-komiser-600' : 'border-gray-200'
className={`flex cursor-pointer flex-col items-center justify-center rounded-lg border-[1.5px] p-6 ${
selected === value
? 'border-komiser-600'
: 'border-gray-200 hover:border-komiser-400'
}`}
>
<Image
Expand Down
128 changes: 91 additions & 37 deletions dashboard/pages/onboarding/database/postgres.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FormEvent, useState } from 'react';
import Head from 'next/head';

import { allDBProviders } from '../../../utils/providerHelper';
Expand All @@ -9,12 +10,47 @@ import OnboardingWizardLayout, {
import LabelledInput from '../../../components/onboarding-wizard/LabelledInput';
import DatabasePurplin from '../../../components/onboarding-wizard/DatabasePurplin';
import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton';
import settingsService from '../../../services/settingsService';
import useToast from '../../../components/toast/hooks/useToast';
import Toast from '../../../components/toast/Toast';
import DatabaseErrorMessage from '../../../components/onboarding-wizard/DatabaseErrorMessage';

export default function PostgreSQLCredentials() {
const database = allDBProviders.POSTGRES;
const databaseProvider = allDBProviders.POSTGRES;

const handleNext = () => {
// TODO: (onboarding-wizard) complete form inputs, validation, submission and navigation
const { toast, setToast, dismissToast } = useToast();

const [isError, setIsError] = useState<boolean>(false);
const [hostname, setHostname] = useState<string>('');
const [database, setDatabase] = useState<string>('');
const [username, setUsername] = useState<string>('');
const [password, setPassword] = useState<string>('');

const handleNext = (e: FormEvent) => {
e.preventDefault();

const payload = JSON.stringify({
type: 'POSTGRES',
hostname,
database,
username,
password
});

settingsService.saveDatabaseConfig(payload).then(res => {
setIsError(false);

if (res === Error) {
setIsError(true);
} else {
setToast({
hasError: false,
title: 'Database connected',
message:
'Your Postgres database has been successfully connected to Komiser.'
});
}
});
};

return (
Expand All @@ -38,45 +74,63 @@ export default function PostgreSQLCredentials() {
</div>
</div>

<div className="flex flex-col space-y-4 py-10">
<div className="space-y-[0.2]">
<LabelledInput
type="text"
id="hostname"
label="Hostname"
subLabel="The server where the Postgres server is hosted"
placeholder="my-postgres-server"
/>
<LabelledInput
type="text"
id="database"
label="Database"
subLabel="The name of the database where Komiser will insert/save the data"
placeholder="my_database"
/>
<LabelledInput
type="text"
id="username"
label="Username"
subLabel="The Postgres username"
placeholder="user"
/>
<LabelledInput
type="text"
id="password"
label="Password"
subLabel="The Postgres password"
placeholder="Example0000*"
/>
</div>
</div>
{isError && <DatabaseErrorMessage />}

<CredentialsButton handleNext={handleNext} nextLabel="Add database" />
<form onSubmit={handleNext}>
<div className="flex flex-col space-y-4 py-10">
<div className="space-y-[0.2]">
<LabelledInput
type="text"
id="hostname"
label="Hostname"
required
value={hostname}
onChange={e => setHostname(e.target.value)}
subLabel="The server where the Postgres server is hosted"
placeholder="my-postgres-server"
/>
<LabelledInput
type="text"
id="database"
label="Database"
required
value={database}
onChange={e => setDatabase(e.target.value)}
subLabel="The name of the database where Komiser will insert/save the data"
placeholder="my_database"
/>
<LabelledInput
type="text"
id="username"
label="Username"
required
value={username}
onChange={e => setUsername(e.target.value)}
subLabel="The Postgres username"
placeholder="user"
/>
<LabelledInput
type="password"
id="password"
label="Password"
required
value={password}
onChange={e => setPassword(e.target.value)}
subLabel="The Postgres password"
placeholder="Example0000*"
/>
</div>
</div>
<CredentialsButton nextLabel="Add database" />
</form>
</LeftSideLayout>

<RightSideLayout>
<DatabasePurplin database={database} />
<DatabasePurplin database={databaseProvider} />
</RightSideLayout>

{/* Toast component */}
{toast && <Toast {...toast} dismissToast={dismissToast} />}
</OnboardingWizardLayout>
</div>
);
Expand Down
Loading

0 comments on commit 791ef40

Please sign in to comment.