Skip to content

Commit

Permalink
feat: allow user to configure a database
Browse files Browse the repository at this point in the history
  • Loading branch information
greghub committed Sep 21, 2023
1 parent e1353a2 commit d2ddce4
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 68 deletions.
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
15 changes: 15 additions & 0 deletions dashboard/components/onboarding-wizard/DatabaseErrorMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
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://docs.komiser.io/welcome/overview" className="underline">
contact our support
</a>{' '}
team for assistance.
</div>
);
}

export default DatabaseErrorMessage;
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
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="text"
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
81 changes: 58 additions & 23 deletions dashboard/pages/onboarding/database/sqlite.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Head from 'next/head';
import { useRef } from 'react';
import { useRef, useState, FormEvent } from 'react';

import { allDBProviders } from '../../../utils/providerHelper';

Expand All @@ -11,12 +11,41 @@ import Folder2Icon from '../../../components/icons/Folder2Icon';
import DatabasePurplin from '../../../components/onboarding-wizard/DatabasePurplin';
import InputFileSelect from '../../../components/onboarding-wizard/InputFileSelect';
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 SqliteCredentials() {
const database = allDBProviders.SQLITE;

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

const [filePath, setFilePath] = useState<string>('');
const [isError, setIsError] = useState<boolean>(false);

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

const payload = JSON.stringify({
type: 'POSTGRES',
filePath
});

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.'
});
}
});
};

const fileInputRef = useRef<HTMLInputElement | null>(null);
Expand All @@ -26,11 +55,6 @@ export default function SqliteCredentials() {
}
};

const handleFileChange = (event: any) => {
const file = event.target.files[0];
// TODO: (onboarding-wizard) handle file change and naming. Set Input field to file.name and use temporary file path for the upload value
};

return (
<div>
<Head>
Expand All @@ -51,28 +75,39 @@ export default function SqliteCredentials() {
</div>
</div>

<div className="flex flex-col space-y-4 py-10">
<div className="space-y-[0.2]">
<InputFileSelect
type="text"
id="file-path-input"
label="File path"
subLabel="Enter the path or browse the file"
placeholder="C:\Documents\Komiser\database"
icon={<Folder2Icon className="h-6 w-6" />}
fileInputRef={fileInputRef}
iconClick={handleButtonClick}
handleFileChange={handleFileChange}
/>
{isError && <DatabaseErrorMessage />}

<form onSubmit={handleNext}>
<div className="flex flex-col space-y-4 py-10">
<div className="space-y-[0.2]">
<InputFileSelect
type="text"
id="file-path-input"
label="File path"
subLabel="Enter the path or browse the file"
placeholder="C:\Documents\Komiser\database"
icon={<Folder2Icon className="h-6 w-6" />}
fileInputRef={fileInputRef}
iconClick={handleButtonClick}
value={filePath}
handleFileChange={e => setFilePath(e.target.files?.[0].name)}
/>
</div>
</div>
</div>

<CredentialsButton handleNext={handleNext} nextLabel="Add database" />
<CredentialsButton
handleNext={handleNext}
nextLabel="Add database"
/>
</form>
</LeftSideLayout>

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

{/* Toast component */}
{toast && <Toast {...toast} dismissToast={dismissToast} />}
</OnboardingWizardLayout>
</div>
);
Expand Down
13 changes: 13 additions & 0 deletions dashboard/services/settingsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,19 @@ const settingsService = {
} catch (error) {
return Error;
}
},

async saveDatabaseConfig(payload: string) {
try {
const res = await fetch(
`${BASE_URL}/databases`,
settings('POST', payload)
);
const data = await res.json();
return data;
} catch (error) {
return Error;
}
}
};

Expand Down

0 comments on commit d2ddce4

Please sign in to comment.