Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
seancolsen committed Dec 18, 2023
1 parent 447f9a9 commit 97b24e3
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 88 deletions.
2 changes: 2 additions & 0 deletions mathesar_ui/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ module.exports = {
'DEFAULT',
'Mathesar.org',
'NULL',
'@',
'/',
'*',
'+',
':',
Expand Down
8 changes: 3 additions & 5 deletions mathesar_ui/src/i18n/languages/en/dict.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"action_cannot_be_undone": "This action cannot be undone",
"actions": "Actions",
"add": "Add",
"add_another": "Add Another",
"add_columns_to_exploration_empty_message": "This exploration does not contain any columns. Edit the exploration to add columns to it.",
"add_connection": "Add Connection",
"add_database_connection": "Add Database Connection",
Expand All @@ -34,7 +33,7 @@
"automatically": "Automatically",
"base_table_exploration_help": "The base table is the table that is being explored and determines the columns that are available for exploration.",
"based_on": "Based on",
"bootstrap_connection_help": "These connection credentials will be used to create the new user. The existing user will need to have CREATEROLE privileges.",
"bootstrap_connection_help": "These connection credentials will be used to create the new user. The existing user will need to have the CREATEROLE privilege.",
"build_your_exploration": "Build your Exploration",
"cancel": "Cancel",
"cannot_modify_own_access_warning": "You cannot modify your own access levels. Please contact an administrator.",
Expand All @@ -47,7 +46,6 @@
"choose_table_or_exploration": "Choose a Table or Exploration",
"clear": "Clear",
"clear_value": "Clear value",
"close": "Close",
"column": "Column",
"column_added_number_of_times": "{count, plural, one {This column has been added once.} other {This column has been added {count} times.}}",
"column_from_table": "[columnName] [fromSlot](from) [tableName]",
Expand Down Expand Up @@ -199,6 +197,7 @@
"inherited": "Inherited",
"inherited_access_level_cannot_remove_warning": "This access level is inherited and cannot be removed from this panel.",
"inspector": "Inspector",
"internal_database": "Internal Database",
"internal_schema_help": "These schemas are necessary for Mathesar to function and will automatically be installed on the database after connecting.",
"join_community_chat": "Join Community Chat",
"join_email_list": "Join Email List",
Expand Down Expand Up @@ -300,9 +299,9 @@
"overridden": "Overridden",
"password": "Password",
"password_encryption_help": "This password will be AES encrypted with Mathesar's secret key and stored in Mathesar's internal database.",
"password_encryption_help_plus_storage": "This password will be AES encrypted with Mathesar's secret key and stored in Mathesar's internal database. Save it elsewhere so that you may also connect to this database from outside Mathesar.",
"passwords_do_not_match": "Passwords do not match",
"permission": "Permission",
"pg_user_password_help": "This password will be AES encrypted with Mathesar's secret key and stored in Mathesar's internal database.",
"pick": "Pick",
"pick_record": "Pick a record",
"pick_table_record": "Pick a Record from [tableName]",
Expand Down Expand Up @@ -409,7 +408,6 @@
"template_type": "Template type",
"ten_best_matches_shown": "The 10 best matches are shown. Continue filtering to see more.",
"the_credentials_will_be_copied_from_this_connection": "The username, password, host, and port will be copied from this connection.",
"then": "Then",
"this_database_must_exist_already": "This database must exist already.",
"this_will_remove_following_columns": "This will remove the following column(s):",
"this_will_remove_following_transformations": "This will remove the following transformation(s):",
Expand Down
115 changes: 42 additions & 73 deletions mathesar_ui/src/systems/connections/AddConnection.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import { assertExhaustive } from '@mathesar/utils/typeUtils';
import GeneralConnection from './GeneralConnection.svelte';
import {
defaultGeneralConnection,
generalConnections,
getConnectionReference,
getUsername,
Expand All @@ -50,11 +51,12 @@
};
const userTypeOptions = ['existing', 'create'] as const;
type UserType = (typeof userTypeOptions)[number];
const userTypeLabels: Record<UserType, string> = {
type UserTypeChoice = (typeof userTypeOptions)[number];
const userTypeLabels: Record<UserTypeChoice, string> = {
existing: $_('use_existing_pg_user'),
create: $_('create_new_pg_user'),
};
type UserType = UserTypeChoice | 'forceExisting';
type InstallationSchema = SampleDataSchemaIdentifier | 'internal';
const installationSchemaOptions: InstallationSchema[] = [
Expand All @@ -74,32 +76,26 @@
movie_collection: $_('sample_data_movies_help'),
};
const nextStepOptions = ['view', 'addAnother', 'close'] as const;
type NextStep = (typeof nextStepOptions)[number];
const nextStepLabels: Record<NextStep, string> = {
view: $_('open'),
addAnother: $_('add_another'),
close: $_('close'),
};
export let onCreate: () => void = () => {};
let nextStep: NextStep = 'view';
export let onExit: () => void;
$: availableConnections = $generalConnections;
$: namedConnections = connectionsStore.connections;
$: connectionNames = new Set($namedConnections.map((c) => c.nickname));
// Common fields
$: credentialsStrategy = requiredField<CredentialsStrategy>('reuse');
$: userType = requiredField<UserType>('existing');
$: credentialsStrategy = requiredField<CredentialsStrategy>(
!!$defaultGeneralConnection ? 'reuse' : 'new',
);
$: userType = requiredField<UserType>(
$defaultGeneralConnection ? 'existing' : 'forceExisting',
);
$: databaseName = requiredField('');
$: createDatabase = requiredField(true);
$: installationSchemas = requiredField<InstallationSchema[]>(['internal']);
$: connectionNickname = requiredField('', [uniqueWith(connectionNames)]);
// Fields for the 'fromKnownConnection' strategy
$: connectionToReuse = requiredField(availableConnections[0]);
$: connectionToReuse = requiredField($defaultGeneralConnection);
// Fields for the 'fromScratch' strategy
$: host = requiredField('');
Expand All @@ -108,7 +104,7 @@
$: existingPassword = requiredField('');
// Fields for the 'withNewUser' strategy
$: bootstrapConnection = requiredField(availableConnections[0]);
$: bootstrapConnection = requiredField($defaultGeneralConnection);
$: newUserName = requiredField('');
$: newPassword = requiredField('');
$: confirmPassword = requiredField('');
Expand All @@ -117,8 +113,8 @@
if ($credentialsStrategy === 'reuse') {
return 'fromKnownConnection' as const;
}
if ($credentialsStrategy === 'new') {
if ($userType === 'existing') {
if ($credentialsStrategy === 'new' || $credentialsStrategy === 'forceNew') {
if ($userType === 'existing' || $userType === 'forceExisting') {
return 'fromScratch' as const;
}
if ($userType === 'create') {
Expand Down Expand Up @@ -170,23 +166,6 @@
return assertExhaustive(overallStrategy);
}
})();
$: allFields = makeForm({
credentialsStrategy,
userType,
databaseName,
createDatabase,
installationSchemas,
connectionNickname,
connectionToReuse,
host,
port,
existingUserName,
existingPassword,
bootstrapConnection,
newUserName,
newPassword,
confirmPassword,
});
$: canCreateDb = $credentialsStrategy === 'reuse' || $userType === 'create';
$: databaseNameHelp = canCreateDb
Expand Down Expand Up @@ -255,7 +234,7 @@
async function saveConnectionDetails() {
try {
await create();
onCreate();
onExit();
toast.success($_('connection_added_successfully'));
} catch (e) {
toast.fromError(e);
Expand All @@ -265,15 +244,17 @@

<div class="db-connection-form">
<GridForm>
<div>{$_('database_server_credentials')}</div>
<div>
<RadioGroup
bind:value={$credentialsStrategy}
ariaLabel={$_('database_server_credentials')}
options={credentialsStrategyOptions}
getRadioLabel={(o) => credentialsStrategyLabels[o]}
/>
</div>
{#if $credentialsStrategy !== 'forceNew'}
<div>{$_('database_server_credentials')}</div>
<div>
<RadioGroup
bind:value={$credentialsStrategy}
ariaLabel={$_('database_server_credentials')}
options={credentialsStrategyOptions}
getRadioLabel={(o) => credentialsStrategyLabels[o]}
/>
</div>
{/if}

{#if $credentialsStrategy === 'reuse'}
<GridFormLabelRow label={$_('known_connection')}>
Expand Down Expand Up @@ -301,15 +282,17 @@
</div>
</GridFormLabelRow>

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

{#if $userType === 'existing'}
<GridFormLabelRow label={$_('user_name')}>
Expand All @@ -323,7 +306,7 @@
<Field
field={existingPassword}
input={{ component: PasswordInput }}
help={$_('pg_user_password_help')}
help={$_('password_encryption_help')}
/>
</GridFormLabelRow>
{:else if $userType === 'create'}
Expand Down Expand Up @@ -351,7 +334,7 @@
<Field
field={confirmPassword}
input={{ component: PasswordInput }}
help={$_('pg_user_password_help')}
help={$_('password_encryption_help_plus_storage')}
/>
</GridFormLabelRow>
{:else}
Expand Down Expand Up @@ -407,19 +390,11 @@
<FormSubmit
{form}
catchErrors
onCancel={() => onExit()}
onProceed={saveConnectionDetails}
proceedButton={{ label: $_('add_connection') }}
cancelButton={{ label: $_('discard_changes') }}
cancelButton={{ label: $_('cancel') }}
/>
<div>
<LabeledInput label={$_('then')}>
<Select
bind:value={nextStep}
options={nextStepOptions}
getLabel={(o) => (o && nextStepLabels[o]) ?? ''}
/>
</LabeledInput>
</div>
</div>
</div>

Expand All @@ -438,10 +413,4 @@
.create-db-checkbox-field {
margin-top: 1rem;
}
.footer {
display: grid;
grid-template: 1fr / 1fr auto;
gap: 1rem;
align-items: center;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
size="large"
title={$_('new_postgresql_database_connection')}
>
<AddConnection onCreate={() => controller.close()} />
<AddConnection onExit={() => controller.close()} />
</ControlledModal>
4 changes: 3 additions & 1 deletion mathesar_ui/src/systems/connections/GeneralConnection.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
({$_('internal_database')})
{/if}
</span>
<span class="uri">{user}@<wbr />{host}:{port}/<wbr />{database}</span>
<span class="uri">
{user}@<wbr />{host}:{port}/<wbr />{database}
</span>
</span>

<style>
Expand Down
48 changes: 40 additions & 8 deletions mathesar_ui/src/systems/connections/generalConnections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,24 @@ import {
type CommonData,
} from '@mathesar/utils/preloadData';

interface UserDatabaseConnection {
type: 'user_database';
connection: ConnectionModel;
}
interface InternalDatabaseConnection {
type: 'internal_database';
connection: CommonData['internal_db_connection'];
}

export type GeneralConnection =
| {
type: 'user_database';
connection: ConnectionModel;
}
| {
type: 'internal_database';
connection: CommonData['internal_db_connection'];
};
| UserDatabaseConnection
| InternalDatabaseConnection;

function isUserDatabaseConnection(
connection: GeneralConnection,
): connection is UserDatabaseConnection {
return connection.type === 'user_database';
}

function getCommonDataGeneralConnections(): GeneralConnection[] {
const commonData = preloadCommonData();
Expand All @@ -42,6 +51,29 @@ export const generalConnections: Readable<GeneralConnection[]> = derived(
],
);

/**
* The connection to pre-select when asking the user what connection they want
* to utilize for managing other connections (e.g. creating a new connection).
*/
export const defaultGeneralConnection = derived(
generalConnections,
(connections) => {
if (connections.length === 0) return undefined;
const internalConnection = connections.find(
(connection) => connection.type === 'internal_database',
);
if (internalConnection) return internalConnection;
const userDatabaseConnections = connections.filter(
isUserDatabaseConnection,
);

// Return the connection with the highest ID
return userDatabaseConnections.reduce((a, b) =>
a.connection.id > b.connection.id ? a : b,
);
},
);

export function getUsername({ connection }: GeneralConnection): string {
return 'user' in connection ? connection.user : connection.username;
}
Expand Down

0 comments on commit 97b24e3

Please sign in to comment.