Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow user to configure a database #985

Merged
merged 1 commit into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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