Skip to content

Commit

Permalink
feat: add connection form ui
Browse files Browse the repository at this point in the history
  • Loading branch information
invm committed Jun 28, 2023
1 parent 5e4264e commit c8a5fc4
Show file tree
Hide file tree
Showing 19 changed files with 403 additions and 239 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"license": "MIT",
"dependencies": {
"@solidjs/router": "^0.8.2",
"@tauri-apps/api": "^1.4.0",
"flowbite": "^1.6.6",
"i": "^0.3.7",
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import 'flowbite';
import './utils/i18n';
import Home from './pages/Home';
import { Route, Router, Routes } from "@solidjs/router"; // 👈 Import the router
import Tabs from './pages/Tabs';

function App() {
document.documentElement.classList.add('dark');
return (
<Home />
<div class="background h-full w-full">
<Router>
<Routes>
<Route path="/" component={Home} />
<Route path="/connection" component={Tabs} />
</Routes>
</Router>
</div>
);
}

Expand Down
59 changes: 0 additions & 59 deletions src/components/AddConnectionForm.tsx

This file was deleted.

208 changes: 102 additions & 106 deletions src/components/AddConnectionsForm/AddConnectionForm.tsx
Original file line number Diff line number Diff line change
@@ -1,148 +1,144 @@
import { Alert, Button, Checkbox, Label, TextInput, Select, Dropdown } from 'flowbite-react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { ConnectionFormInput, ConnectionFormSchema } from '.';
import { Alert, Button, Checkbox, Label, TextInput, Select } from '../UI';
import { ConnectionFormSchema } from '.';
import { ConnectionColor, connectionColors, Scheme, schemes } from '../../interfaces';
import { titleCase } from '../../utils/formatters';
import { useFormHandler } from 'solid-form-handler';
import { zodSchema } from 'solid-form-handler/zod';
import { t } from 'i18next';
import { onMount } from 'solid-js';

const ColorCircle = ({ color }: { color: ConnectionColor }) => {
return <span style={{ width: 20, height: 20, borderRadius: '50%', margin: 8 }} className={`bg-${color}-500`}></span>
const ColorCircle = (props: { color: ConnectionColor }) => {
return <span class={`min-w-[20px] min-h-[20px] mb-1 rounded-full border-2 bg-${props.color}-500`}></span>
}

const defaultValues = {
connection_name: '',
scheme: Scheme.MySQL,
port: 3306,
color: 'orange',
host: '',
username: '',
password: '',
save_password: false,
dbname: '',
params: '',
}

const AddConnectionForm = () => {
const { t } = useTranslation();
const {
register,
handleSubmit,
formState: { errors, isDirty, isValid, isLoading, isSubmitting },
setValue,
watch,
} = useForm<ConnectionFormInput>({
resolver: zodResolver(ConnectionFormSchema),
defaultValues: {
connection_name: '',
scheme: Scheme.MySQL,
port: 3306,
color: 'orange',
host: '',
username: '',
password: '',
save_password: false,
dbname: '',
params: '',
},
const formHandler = useFormHandler(zodSchema(ConnectionFormSchema), {
delay: 300,
});
const { formData, isFormInvalid, setFieldDefaultValue, getFormErrors, setFieldValue } = formHandler;

onMount(() => {
for (const key in defaultValues) {
setFieldDefaultValue(key, defaultValues[key as keyof typeof defaultValues]);
}
});

const onSubmit = (data: ConnectionFormInput) => {
console.log(data)
const submit = async (event: Event) => {
event.preventDefault();
try {
await formHandler.validateForm();
alert('Data sent with success: ' + JSON.stringify(formData()));
formHandler.resetForm();
} catch (error) {
console.error(error);
}
};

const theme = {
field: { input: { sizes: { sm: "text-md py-1 px-2 font-bold" } } }
}

return (
<div className="flex-2 p-3 max-w-lg">
<form className="flex w-full flex-col gap-1"
onSubmit={handleSubmit(onSubmit)}>
<div class="flex-2 p-3 max-w-lg">
<form class="flex w-full flex-col gap-1" autocomplete="off" onSubmit={submit}>
<div>
<h2 className="text-2xl font-bold text">{t('components.add_connection_form.title')}</h2>
<h2 class="text-2xl font-bold text">{t('components.add_connection_form.title')}</h2>
</div>
<div className='flex gap-3'>
<div className='w-full'>
<div className="mb-2 block">
<Label htmlFor="connection_name" value={t('components.add_connection_form.labels.connection_name')}
/>
</div>
<TextInput {...register('connection_name')} sizing="sm" theme={theme} id="connection_name" minLength={2} maxLength={255} />
<div class='flex gap-3'>
<div class='w-full'>
<TextInput
label={t('components.add_connection_form.labels.connection_name')}
name="connection_name" formHandler={formHandler}
id="connection_name" minLength={2} maxLength={255} />
</div>
<div>
<div className='w-full flex flex-col justify-stretch items-stretch'>
<div className="my-1 block">
<Label htmlFor="rolor" value={t('components.add_connection_form.labels.color')} />
</div>
<div className="flex items-center gap-3">
<ColorCircle {...{ color: watch('color') }} />
<Dropdown theme={{ "arrowIcon": "ml-2 h-4 w-4 text" }} placement="bottom" id="color" inline size="sm" className="h-60 py-2 overflow-y-auto" label="">
{connectionColors.map((color, i) => (
<Dropdown.Item key={color + i} onClick={() => setValue('color', color)}>
<ColorCircle {...{ color }} />
{titleCase(color)}
</Dropdown.Item>
))}
</Dropdown>
<div class="w-2/5">
<div class='w-full flex flex-col justify-stretch items-stretch'>
<div class="flex items-end gap-3">
<ColorCircle color={formData().color} />
<Select
label={t('components.add_connection_form.labels.color')}
name="color"
options={connectionColors.map((color) => ({ value: color, label: titleCase(color) }))}
formHandler={formHandler}
/>
</div>
</div>
</div>
</div>
<div className="flex gap-3">
<div className='w-3/4'>
<div className="my-1 block">
<Label htmlFor="scheme" value={t('components.add_connection_form.labels.scheme')} />
</div>
<Select id="scheme" required sizing="sm" >
{schemes.map((scheme) => (<option key={scheme}>{scheme}</option>))}
</Select>
<div class="flex gap-3">
<div class='w-3/4'>
<Select
id="scheme"
label={t('components.add_connection_form.labels.scheme')}
options={schemes.map((sc) => ({ value: sc, label: titleCase(sc) }))}
formHandler={formHandler}
/>
</div>
<div className='w-1/4'>
<div className="my-1 block">
<Label htmlFor="port" value={t('components.add_connection_form.labels.port')} />
</div>
<TextInput {...register('port', { valueAsNumber: true, min: 1, max: 65335 })} sizing="sm" id="port" />
<div class='w-1/4'>
<TextInput
label={t('components.add_connection_form.labels.port')}
name="port" id="port" formHandler={formHandler} type="number"
min={1} max={65335} />
</div>
</div>
<div className="flex gap-3">
<div className='w-3/4'>
<div className="my-1 block">
<Label htmlFor="host" value={t('components.add_connection_form.labels.host')} />
</div>
<TextInput {...register('host')} sizing="sm" id="host" />
<div class="flex gap-3">
<div class='w-3/4'>
<TextInput
label={t('components.add_connection_form.labels.host')}
min={1} max={255}
name="host" id="host" formHandler={formHandler}
/>
</div>
<div className='w-1/4'>
<div className="my-1 block">
<Label htmlFor="dbname" value={t('components.add_connection_form.labels.dbname')} />
</div>
<TextInput {...register('dbname')} sizing="sm" id="dbname" />
<div class='w-1/4'>
<TextInput
label={t('components.add_connection_form.labels.dbname')}
min={1} max={255}
name="dbname" id="dbname" formHandler={formHandler} />
</div>
</div>

<div className="grid grid-cols-2 gap-3">
<div className='w-full'>
<div className="my-1 block">
<Label htmlFor="username" value={t('components.add_connection_form.labels.username')} />
</div>
<TextInput {...register('username')} sizing="sm" id="username" />
<div class="grid grid-cols-2 gap-3">
<div class='w-full'>
<TextInput
label={t('components.add_connection_form.labels.username')}
min={1} max={255}
name="username" id="username" formHandler={formHandler} />
</div>
<div className='w-full'>
<div className="my-1 block">
<Label htmlFor="password" value={t('components.add_connection_form.labels.password')} />
</div>
<TextInput {...register('password')} type="password" sizing="sm" id="password" />
<div class='w-full'>
<TextInput
label={t('components.add_connection_form.labels.password')}
name="password" id="password"
min={1} max={255}
formHandler={formHandler} type="password" />
</div>
</div>
<div className="flex items-center gap-2 my-2">
<Checkbox id="save_password" {...register('save_password')} />
<Label htmlFor="save_password">
{t('components.add_connection_form.labels.save_password')}
</Label>
<div class="flex items-center gap-2 my-2">
<Checkbox label={t('components.add_connection_form.labels.save_password')} id="save_password" formHandler={formHandler} />
</div>
<div>
<Alert color="failure" className="py-2">
<Alert color="error">
<>
{Object.entries(errors).map(([key, { message }]) => (
<p key={key} className="text-bold">
{t(`components.add_connection_form.labels.${key}`)}: {message}
{getFormErrors().map((error) => (
<p class="text-bold">
{t(`components.add_connection_form.labels.${error.path}`)}: {error.message}
</p>
))}
</>
</Alert>
</div>
<Button disabled={!isDirty || isLoading || isSubmitting} type="submit" size="sm">{t('components.add_connection_form.title')}</Button>
<Button disabled={!isFormInvalid} type="submit" >{t('components.add_connection_form.title')}</Button>
</form>
</div>
)
}

export default AddConnectionForm
export { AddConnectionForm }
3 changes: 1 addition & 2 deletions src/components/AddConnectionsForm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,4 @@ export const ConnectionFormSchema = z.object({
params: z.string().optional(),
});

export type ConnectionFormInput = z.infer<typeof ConnectionFormSchema>;

export * from './AddConnectionForm'
Loading

0 comments on commit c8a5fc4

Please sign in to comment.