Skip to content

Commit

Permalink
WIP add more fields
Browse files Browse the repository at this point in the history
  • Loading branch information
seancolsen committed Nov 22, 2023
1 parent 2cf2a56 commit 58533d2
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.fieldset-group {
padding: 0;
margin: 0;
--spacing-y-default: 0.5em;
--spacing-x-default: 1em;

Expand Down
15 changes: 4 additions & 11 deletions mathesar_ui/src/components/form/Field.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import { LabeledInput, TextInput } from '@mathesar-component-library';
import type { ComponentWithProps } from '@mathesar-component-library/types';
import type { FieldStore } from './field';
import FieldErrors from './FieldErrors.svelte';
import FieldHelp from './FieldHelp.svelte';
import FieldLayout from './FieldLayout.svelte';
import type { FieldStore } from './field';
type Layout = ComponentProps<LabeledInput>['layout'];
type Value = $$Generic;
Expand Down Expand Up @@ -47,18 +48,10 @@
<slot />
</svelte:component>
{#if help || $$slots.help}
<div class="help">
<FieldHelp>
<slot name="help">{help}</slot>
</div>
</FieldHelp>
{/if}
{/if}
<FieldErrors {field} />
</FieldLayout>

<style>
.help {
font-size: var(--text-size-small);
color: var(--color-text-muted);
margin-top: 0.5rem;
}
</style>
10 changes: 10 additions & 0 deletions mathesar_ui/src/components/form/FieldHelp.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<span class="field-help"><slot /></span>

<style>
.field-help {
display: block;
font-size: var(--text-size-small);
color: var(--color-text-muted);
margin-top: 0.5rem;
}
</style>
11 changes: 10 additions & 1 deletion mathesar_ui/src/i18n/languages/en/dict.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
{
"add_connection": "Add Connection",
"bootstrap_connection_help": "These connection credentials will be used to create the new user. The existing user will need to have CREATEROLE privileges.",
"confirm_password": "Confirm password",
"connection_nickname": "Connection nickname",
"connection_nickname_help": "This nickname will appear in Mathesar's navigation and must be unique across all connections. You can change it later.",
"copy_and_paste_text": "Copy and Paste Text",
"create_a_table_by_importing": "Create a table by importing your data",
"create_db_if_not_exists": "Create this database if it does not already exist",
"create_new_pg_user": "Create a new PostgreSQL user",
"create_user_via": "Create user via",
"data_source": "Data Source",
"database_name": "Database name",
"database_server_credentials": "Database server credentials",
"discard_changes": "Discard Changes",
"enter_new_credentials": "Enter new credentials",
"existing_pg_user_privileges_help": "The user will need to have CONNECT and CREATE privileges on the database.",
"host_name": "Host name",
"import": "Import",
"internal_schema_help": "These schemas are necessary for Mathesar to function and will automatically be installed on the database after connecting.",
"known_connection": "Known connection",
"large_data_takes_time_warning": "Large data sets can sometimes take several minutes to process. Please do not leave this page or close the browser tab while the import is in progress.",
"linking_table": "Linking Table",
"many_to_many": "Many to Many",
"many_to_many_link_description": "Multiple [baseTable] and [targetTable] records can link to each other through a new [mappingTable]",
"many_to_many_self_referential_link_description": "Multiple [baseTable] records can link to each other through a new [mapping]",
"many_to_one": "Many to One",
"many_to_one_link_description": "Multiple [baseTable] records can link to the same [targetTable] record.",
"new_pg_user_privileges_help": "The user will need to have CONNECT and CREATE privileges on the database.",
"new_password": "New password",
"new_pg_user_privileges_help": "The user will be granted CONNECT and CREATE privileges on the database.",
"new_user_name": "New user name",
"no_file_uploaded": "No file uploaded",
"no_matches": "No matches for [searchValue]",
"number_of_matches": "{count, plural, one {{count} match for [searchValue] {categoryCount, plural, one {in [categoryName]} other{}}} other {{count} matches for [searchValue] {categoryCount, plural, one {in [categoryName]} other{}}}}",
Expand All @@ -35,6 +43,7 @@
"sample_data_library_help": "Sample data from a fictional library.",
"sample_data_movies_help": "Sample data from a collection of movies.",
"schemas_to_install": "Schemas to install",
"the_credentials_will_be_copied_from_this_connection": "The username, password, host, and port will be copied from this connection.",
"this_database_must_exist_already": "This database must exist already.",
"upload_a_file": "Upload a file",
"use_existing_pg_user": "Use an existing PostgreSQL user",
Expand Down
164 changes: 130 additions & 34 deletions mathesar_ui/src/pages/database-connection/DatabaseConnectionForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
import GridForm from './GridForm.svelte';

Check failure on line 19 in mathesar_ui/src/pages/database-connection/DatabaseConnectionForm.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

`./GridForm.svelte` import should occur after import of `@mathesar/utils/typeUtils`
import GridFormDivider from './GridFormDivider.svelte';

Check failure on line 20 in mathesar_ui/src/pages/database-connection/DatabaseConnectionForm.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

`./GridFormDivider.svelte` import should occur after import of `@mathesar/utils/typeUtils`
import GridFormLabelRow from './GridFormLabelRow.svelte';

Check failure on line 21 in mathesar_ui/src/pages/database-connection/DatabaseConnectionForm.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

`./GridFormLabelRow.svelte` import should occur after import of `@mathesar/utils/typeUtils`
import LabeledInput from '@mathesar/component-library/labeled-input/LabeledInput.svelte';
import Checkbox from '@mathesar/component-library/checkbox/Checkbox.svelte';
import Select from '@mathesar/component-library/select/Select.svelte';
import FieldHelp from '@mathesar/components/form/FieldHelp.svelte';
import { assertExhaustive } from '@mathesar/utils/typeUtils';
const credentialsStrategyOptions = ['reuse', 'new'] as const;
type CredentialsStrategy = typeof credentialsStrategyOptions[number];
Expand Down Expand Up @@ -49,6 +54,26 @@
movies: $_('sample_data_movies_help'),
};
// TODO clean up using a type defined from the API once we have one
interface C {
database: string;
user: string;
host: string;
port: string;
}
const bootstrapConnectionOptions: C[] = [
{
user: 'mathesar',
host: 'localhost',
port: '5432',
database: 'mathesar_django',
},
];
function getConnectionLabel(c: C | undefined) {
if (!c) return '';
return `${c.user}@${c.host}:${c.port}/${c.database}`;
}
export let onCreate: ((db: Database) => Promise<void>) | undefined =
undefined;
Expand All @@ -60,18 +85,28 @@
$: username = requiredField('');
$: host = requiredField('');
$: port = requiredField(5432);
$: password = requiredField('');
$: userName = requiredField('');
$: bootstrapConnection = requiredField(bootstrapConnectionOptions[0]);
$: existingPassword = requiredField('');
$: newPassword = requiredField('');
$: confirmPassword = requiredField('');
$: existingUserName = requiredField('');
$: newUserName = requiredField('');
$: createDatabase = requiredField(true);
$: formFields = {
connectionName,
databaseName,
username,
host,
port,
password,
password: existingPassword,
};
$: form = makeForm(formFields);
$: canCreateDb = $credentialsStrategy === 'reuse' || $userType === 'create';
$: databaseNameHelp = canCreateDb
? undefined
: $_('this_database_must_exist_already');
async function addNewDatabaseConnection() {
const formValues = $form.values;
return databaseConnectionApi.add({
Expand Down Expand Up @@ -125,46 +160,104 @@
/>
</div>

<GridFormLabelRow label={$_('host_name')}>
<div class="host-and-port">
<Field field={host} />
<Field
field={port}
input={{ component: NumberInput, props: { style: 'width: 8ch;' } }}
label={$_('port')}
{#if $credentialsStrategy === 'reuse'}
<GridFormLabelRow label={$_('known_connection')}>
<Select
bind:value={$bootstrapConnection}
options={bootstrapConnectionOptions}
getLabel={getConnectionLabel}
/>
<FieldHelp>
{$_('the_credentials_will_be_copied_from_this_connection')}
</FieldHelp>
</GridFormLabelRow>
{:else if $credentialsStrategy === 'new'}
<GridFormLabelRow label={$_('host_name')}>
<div class="host-and-port">
<Field field={host} />
<Field
field={port}
input={{ component: NumberInput, props: { style: 'width: 8ch;' } }}
label={$_('port')}
/>
</div>
</GridFormLabelRow>

<div>{$_('user_type')}</div>
<div>
<RadioGroup
bind:value={$userType}
ariaLabel={$_('user_type')}
options={userTypeOptions}
getRadioLabel={(o) => userTypeLabels[o]}
/>
</div>
</GridFormLabelRow>

<div>{$_('user_type')}</div>
<div>
<RadioGroup
bind:value={$userType}
ariaLabel={$_('user_type')}
options={userTypeOptions}
getRadioLabel={(o) => userTypeLabels[o]}
/>
</div>
{#if $userType === 'existing'}
<GridFormLabelRow label={$_('user_name')}>
<Field
field={existingUserName}
help={$_('existing_pg_user_privileges_help')}
/>
</GridFormLabelRow>

<GridFormLabelRow label={$_('user_name')}>
<Field field={userName} help={$_('new_pg_user_privileges_help')} />
</GridFormLabelRow>
<GridFormLabelRow label={$_('password')}>
<Field
field={existingPassword}
input={{ component: PasswordInput }}
help={$_('pg_user_password_help')}
/>
</GridFormLabelRow>
{:else if $userType === 'create'}
<GridFormLabelRow label={$_('create_user_via')}>
<!-- TODO: handle overflow when option label is very long -->
<Select
bind:value={$bootstrapConnection}
options={bootstrapConnectionOptions}
getLabel={getConnectionLabel}
/>
<FieldHelp>{$_('bootstrap_connection_help')}</FieldHelp>
</GridFormLabelRow>

<GridFormLabelRow label={$_('password')}>
<Field
field={password}
input={{ component: PasswordInput }}
help={$_('pg_user_password_help')}
/>
</GridFormLabelRow>
<GridFormLabelRow label={$_('new_user_name')}>
<Field field={newUserName} help={$_('new_pg_user_privileges_help')} />
</GridFormLabelRow>

<GridFormLabelRow label={$_('new_password')}>
<Field field={newPassword} input={{ component: PasswordInput }} />
</GridFormLabelRow>

<GridFormLabelRow label={$_('confirm_password')}>
<Field
field={confirmPassword}
input={{ component: PasswordInput }}
help={$_('pg_user_password_help')}
/>
</GridFormLabelRow>
{:else}
{assertExhaustive($userType)}
{/if}
{:else}
{assertExhaustive($credentialsStrategy)}
{/if}

<GridFormDivider />

<GridFormLabelRow label={$_('database_name')}>
<Field
field={databaseName}
help={$_('this_database_must_exist_already')}
/>
<div>
<Field field={databaseName} help={databaseNameHelp} />
</div>
{#if canCreateDb}
<div class="create-db-checkbox-field">
<LabeledInput
label={$_('create_db_if_not_exists')}
layout="inline-input-first"
help={$_('TODO')}
>
<Checkbox bind:checked={$createDatabase} />
</LabeledInput>
</div>
{/if}
</GridFormLabelRow>

<GridFormDivider />
Expand Down Expand Up @@ -210,4 +303,7 @@
.host-and-port > :global(*) {
margin: 0;
}
.create-db-checkbox-field {
margin-top: 1rem;
}
</style>

0 comments on commit 58533d2

Please sign in to comment.