From 012ef3b70039c70e82c2fca2b6acc76662f7ce4a Mon Sep 17 00:00:00 2001 From: Sean Colsen Date: Tue, 19 Nov 2024 15:36:19 -0500 Subject: [PATCH 01/27] Improve Database Settings UI --- .../component-library/button/Button.svelte | 62 ++++++--- .../spinner-button/SpinnerButton.svelte | 3 + .../PhraseContainingIdentifier.svelte | 3 +- mathesar_ui/src/components/Yes.svelte | 28 +++++ mathesar_ui/src/i18n/languages/en/dict.json | 31 +++-- mathesar_ui/src/icons/index.ts | 2 +- .../pages/database/DatabasePageWrapper.svelte | 2 +- .../database/schemas/SchemasSection.svelte | 18 --- .../database/settings/SettingsWrapper.svelte | 31 ++--- .../collaborators/CollaboratorRow.svelte | 34 ++++- .../collaborators/Collaborators.svelte | 1 + .../EditRoleForCollaboratorModal.svelte | 12 +- .../RemoveCollaboratorBody.svelte | 36 ++++++ .../RemoveCollaboratorTitle.svelte | 20 +++ .../ConfigureRoleModal.svelte | 12 +- .../RoleConfiguration.svelte | 118 ++++++++++-------- .../settings/roles/ModifyRoleMembers.svelte | 12 +- .../database/settings/roles/RoleRow.svelte | 50 +++++--- .../src/routes/DatabaseSettingsRoute.svelte | 2 +- 19 files changed, 325 insertions(+), 152 deletions(-) create mode 100644 mathesar_ui/src/components/Yes.svelte create mode 100644 mathesar_ui/src/pages/database/settings/collaborators/RemoveCollaboratorBody.svelte create mode 100644 mathesar_ui/src/pages/database/settings/collaborators/RemoveCollaboratorTitle.svelte diff --git a/mathesar_ui/src/component-library/button/Button.svelte b/mathesar_ui/src/component-library/button/Button.svelte index 61e7bf989a..b98375b3f3 100644 --- a/mathesar_ui/src/component-library/button/Button.svelte +++ b/mathesar_ui/src/component-library/button/Button.svelte @@ -4,6 +4,8 @@ Size, } from '@mathesar-component-library-dir/commonTypes'; + import Tooltip from '../tooltip/Tooltip.svelte'; + /** * Button appearance. One of: 'default', 'primary', 'secondary', 'plain', 'ghost'. * @required @@ -26,25 +28,51 @@ // Underlying DOM element for direct access export let element: HTMLElement | undefined = undefined; + export let tooltip: string | undefined = undefined; + $: allClasses = ['btn', `btn-${appearance}`, `size-${size}`, classes].join( ' ', ); - +{#if tooltip || $$slots.tooltip} + + +
{tooltip}
+
+{:else} + +{/if} diff --git a/mathesar_ui/src/component-library/spinner-button/SpinnerButton.svelte b/mathesar_ui/src/component-library/spinner-button/SpinnerButton.svelte index faad65e6d1..93a12edfa6 100644 --- a/mathesar_ui/src/component-library/spinner-button/SpinnerButton.svelte +++ b/mathesar_ui/src/component-library/spinner-button/SpinnerButton.svelte @@ -31,6 +31,7 @@ export let disabled = false; export let isProcessing = false; export let appearance: Appearance = 'primary'; + export let tooltip: string | undefined = undefined; /** * Bind to this function if you want to be able to programmatically call the @@ -55,6 +56,8 @@ on:click={proceed} {appearance} disabled={disabled || isProcessing} + {tooltip} + aria-label={label ? undefined : tooltip} {...$$restProps} > {#if isProcessing} diff --git a/mathesar_ui/src/components/PhraseContainingIdentifier.svelte b/mathesar_ui/src/components/PhraseContainingIdentifier.svelte index fac4b747ee..b034bc2af1 100644 --- a/mathesar_ui/src/components/PhraseContainingIdentifier.svelte +++ b/mathesar_ui/src/components/PhraseContainingIdentifier.svelte @@ -4,10 +4,11 @@ export let identifier: string; export let wrappingString = ''; + export let identifierKey = 'identifier'; - {#if slotName === 'identifier'} + {#if slotName === identifierKey} {identifier} {/if} diff --git a/mathesar_ui/src/components/Yes.svelte b/mathesar_ui/src/components/Yes.svelte new file mode 100644 index 0000000000..7fc912495e --- /dev/null +++ b/mathesar_ui/src/components/Yes.svelte @@ -0,0 +1,28 @@ + + + + + + + diff --git a/mathesar_ui/src/i18n/languages/en/dict.json b/mathesar_ui/src/i18n/languages/en/dict.json index 541c66129e..8747b9ef31 100644 --- a/mathesar_ui/src/i18n/languages/en/dict.json +++ b/mathesar_ui/src/i18n/languages/en/dict.json @@ -54,6 +54,7 @@ "cannot_move_linked_column_to_linked_table": "Cannot move linking column \"{columnName}\" to its linked table \"{tableName}\".", "cell": "Cell", "change_password": "Change Password", + "change_role": "Change Role", "check_for_updates": "Check for Updates", "child_roles": "Child Roles", "child_roles_count": "{count, plural, one {{count} child role} other {{count} child roles}}", @@ -96,8 +97,6 @@ "columns_to_move": "Columns to Move", "columns_unique_values_help": "The columns in this table that should contain unique values.", "configure_in_mathesar": "Configure in Mathesar", - "configure_password": "Configure Password", - "configure_value": "Configure ''{value}''", "confirm_and_create_table": "Confirm & create table", "confirm_delete_table": "To confirm the deletion of the [tableName] table, please enter the table name into the input field below.", "confirm_password": "Confirm Password", @@ -166,6 +165,7 @@ "database_privilege_create_help": "Allow creation of new schemas.", "database_privilege_temporary_help": "Allow creation of temporary tables.", "database_server_credentials": "Database server credentials", + "database_settings": "Database Settings", "database_type": "Database Type", "databases": "Databases", "databases_matching_search": "{count, plural, one {{count} database matches [searchValue]} other {{count} databases match [searchValue]}}", @@ -208,15 +208,16 @@ "display_name": "Display Name", "documentation_and_resources": "Documentation & Resources", "drop_role": "Drop Role", + "drop_role_name": "Drop role [name]", + "drop_role_name_question": "Drop role [name]?", "drop_role_warning": "This role will be dropped on the database server and will not be available for any databases configured on the same server.", - "drop_role_with_identifier": "Drop Role [identifier]?", "edit": "Edit", - "edit_child_roles_for_parent": "Edit Child Roles for ''{parent}''", + "edit_child_roles_for_parent": "Edit [parent] child roles", "edit_connection": "Edit Connection", "edit_connection_with_name": "Edit Connection: [connectionName]", "edit_exploration_attempt_recovery": "You can edit the exploration in the Data Explorer to attempt recovering it.", "edit_in_data_explorer": "Edit in Data Explorer", - "edit_role_for_collaborator_value": "Edit Role for ''{collaborator}''", + "edit_role_for_collaborator_value": "Change Role for [userName]", "edit_schema": "Edit Schema", "edit_schema_with_name": "Edit Schema [schemaName]", "edit_table": "Edit Table", @@ -292,6 +293,7 @@ "import": "Import", "import_from_file": "Import from a File", "in_mathesar": "In Mathesar", + "in_postgresql": "In PostgreSQL", "in_this_table": "In this table", "individual_permissions_admin_modify_warning": "Individual permissions cannot be modified for users with Admin access.", "inherited": "Inherited", @@ -408,7 +410,6 @@ "number_of_matches_in_category": "{count, plural, one {{count} match for [searchValue] in [categoryName]} other {{count} matches for [searchValue] in [categoryName]}}", "old_password": "Old Password", "oldest_to_newest_sort": "Oldest-Newest", - "on_the_server": "On The Server", "one_column_from_base_is_required": "At least one column from the base table is required to add columns from linked tables.", "one_to_many": "One to Many", "one_to_many_link_desc": "One [baseTable] record can be linked from multiple [targetTable] records.", @@ -429,6 +430,7 @@ "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.", + "password_stored": "Password Stored", "passwords_do_not_match": "Passwords do not match", "paste_data_import": "Paste the data you want to import", "permission": "Permission", @@ -476,12 +478,18 @@ "release_notes_and_upgrade_instructions": "Release Notes and Upgrade Instructions", "released_date": "Released {date}", "remove": "Remove", + "remove_collaborator": "Remove Collaborator", + "remove_collaborator_body_1": "The user [userName] will no longer have access to the [databaseName] database.", + "remove_collaborator_body_2": "The user [userName] will still be able to log in to Mathesar and might still have access to other connected databases.", + "remove_collaborator_body_3": "The associated PostgreSQL role [roleName] will be unaffected.", + "remove_collaborator_name_from_database_question": "Remove [userName] as a collaborator on the [databaseName] database?", "remove_configuration": "Remove Configuration", - "remove_configuration_for_identifier": "Remove Configuration for [identifier]?", "remove_filters": "{count, plural, one {Remove Filter} other {Remove {count} Filters}}", "remove_grouping": "Remove Grouping", "remove_old_link_create_new": "Remove old link and create a new link?", "remove_sorting_type": "Remove {sortingType} Sorting", + "remove_stored_password": "Remove Stored Password", + "remove_stored_password_for_identifier": "Remove Stored Password for [identifier]?", "removing_role_configuration_warning": "Removing this configuration will prevent collaborators assigned to this role from accessing databases on server ''{server}''.", "reset": "Reset", "restrict_to_unique": "Restrict to Unique", @@ -491,9 +499,8 @@ "retry": "Retry", "reuse_credentials_from_known_connection": "Reuse credentials from a known connection", "role": "Role", - "role_configuration": "Role Configuration", "role_configuration_removed": "The role configuration has been removed successfully", - "role_configured_all_databases_in_server": "This role will be configured for all databases on DB Server ''{server}''", + "role_configured_all_databases_in_server": "The new password will be used for this role when connecting to any databases on server ''{server}''", "role_configured_successfully": "Role configured successfully", "role_configured_successfully_new_password": "Role configured successfully with new password", "role_created_successfully": "The Role has been created successfully", @@ -509,6 +516,7 @@ "save": "Save", "save_and_close": "Save and Close", "save_exploration": "Save Exploration", + "save_password": "Save Password", "saved_explorations": "Saved Explorations", "saving": "Saving", "saving_changes": "Saving Changes", @@ -575,6 +583,9 @@ "start_over": "Start Over", "start_working_with_mathesar": "Start Working with Mathesar", "static_record_summary_template_error": "Record summary cannot be static. Add at least one column field in order to save.", + "store_a_password": "Store a Password", + "stored_password": "Stored Password", + "stored_role_passwords": "Stored Role Passwords", "summarization": "Summarization", "summarize": "Summarize", "summarize_column_configure": "You can manually configure a summarization later via the \"Transform Results\" pane.", @@ -650,6 +661,8 @@ "unsaved_changes": "Unsaved Changes", "update": "Update", "update_connection": "Update Connection", + "update_stored_password": "Update Stored Password", + "update_stored_password_for_role": "Set a stored password for [role]", "upgrade": "Upgrade", "upgrade_in_progress_do_not_navigate": "A Mathesar upgrade is currently in progress. It is important that you do not navigate away from this page until the upgrade is complete.", "upgrade_to_version": "Upgrade to {version}", diff --git a/mathesar_ui/src/icons/index.ts b/mathesar_ui/src/icons/index.ts index 987c85524a..8fda77ae54 100644 --- a/mathesar_ui/src/icons/index.ts +++ b/mathesar_ui/src/icons/index.ts @@ -106,7 +106,6 @@ export const iconAddFilter: IconProps = { data: faFilter }; export const iconAddNew: IconProps = { data: faPlus }; export const iconAddUser: IconProps = { data: faUserPlus }; export const iconConfigure: IconProps = { data: faCogs }; -export const iconConfigurePassword = { data: faKey }; export const iconConnectDatabase = { data: connectDatabaseIcon }; export const iconCopyMajor: IconProps = { data: faCopy }; /** TODO: use faBinary once it's available (via newer FontAwesome version) */ @@ -199,6 +198,7 @@ export const iconFieldDelimiter: IconProps = { data: faCaretRight }; export const iconNotEditable: IconProps = { data: faLock }; export const iconUnsavedChanges: IconProps = { data: faCircleExclamation }; +export const iconYes: IconProps = { data: faCheck }; // UI TYPES diff --git a/mathesar_ui/src/pages/database/DatabasePageWrapper.svelte b/mathesar_ui/src/pages/database/DatabasePageWrapper.svelte index 5c20d303c4..69233a395b 100644 --- a/mathesar_ui/src/pages/database/DatabasePageWrapper.svelte +++ b/mathesar_ui/src/pages/database/DatabasePageWrapper.svelte @@ -60,7 +60,7 @@ }, { id: 'settings', - label: $_('settings'), + label: $_('database_settings'), href: getDatabasePageSettingsSectionUrl(database.id), }, ]; diff --git a/mathesar_ui/src/pages/database/schemas/SchemasSection.svelte b/mathesar_ui/src/pages/database/schemas/SchemasSection.svelte index a911f24042..7ec087d1d5 100644 --- a/mathesar_ui/src/pages/database/schemas/SchemasSection.svelte +++ b/mathesar_ui/src/pages/database/schemas/SchemasSection.svelte @@ -83,12 +83,6 @@
-
-

- {$_('schemas')} - {schemasMap.size ? `(${schemasMap.size})` : ''} -

-
@@ -67,13 +69,12 @@ padding: var(--size-x-small) 0; .heading { - font-size: var(--text-size-small); + color: var(--slate-400); font-weight: 500; - text-transform: uppercase; margin-bottom: var(--size-ultra-small); } .menu-divider { - margin: 0.5rem 0.1rem 0.8rem 0.1rem; + margin: 1rem 0; } } diff --git a/mathesar_ui/src/pages/database/settings/collaborators/CollaboratorRow.svelte b/mathesar_ui/src/pages/database/settings/collaborators/CollaboratorRow.svelte index 076a27e7e3..7b57eb2433 100644 --- a/mathesar_ui/src/pages/database/settings/collaborators/CollaboratorRow.svelte +++ b/mathesar_ui/src/pages/database/settings/collaborators/CollaboratorRow.svelte @@ -6,12 +6,17 @@ import { DatabaseSettingsRouteContext } from '@mathesar/contexts/DatabaseSettingsRouteContext'; import { iconDeleteMajor, iconEdit } from '@mathesar/icons'; import type { Collaborator } from '@mathesar/models/Collaborator'; - import { confirmDelete } from '@mathesar/stores/confirmation'; + import type { Database } from '@mathesar/models/Database'; + import { confirm } from '@mathesar/stores/confirmation'; import { toast } from '@mathesar/stores/toast'; import { getUserProfileStoreFromContext } from '@mathesar/stores/userProfile'; import { Button, SpinnerButton } from '@mathesar-component-library'; + import RemoveCollaboratorBody from './RemoveCollaboratorBody.svelte'; + import RemoveCollaboratorTitle from './RemoveCollaboratorTitle.svelte'; + export let collaborator: Collaborator; + export let database: Pick; export let onClickEditRole: (collaborator: Collaborator) => void; export let onDelete: (collaborator: Collaborator) => void; @@ -57,23 +62,42 @@ appearance="secondary" on:click={() => onClickEditRole(collaborator)} disabled={!isMathesarAdmin} + tooltip={$_('change_role')} >
+ - confirmDelete({ - identifierName: userName, - identifierType: $_('collaborator'), + confirm({ + title: { + component: RemoveCollaboratorTitle, + props: { + userName, + databaseName: database.name, + }, + }, + body: { + component: RemoveCollaboratorBody, + props: { + userName, + databaseName: database.name, + roleName: configuredRole?.name, + }, + }, + proceedButton: { + label: $_('remove_collaborator'), + }, })} onClick={deleteCollaborator} icon={{ ...iconDeleteMajor, size: '0.8em' }} label="" - appearance="secondary" + tooltip={$_('remove_collaborator')} disabled={!isMathesarAdmin} /> diff --git a/mathesar_ui/src/pages/database/settings/collaborators/Collaborators.svelte b/mathesar_ui/src/pages/database/settings/collaborators/Collaborators.svelte index 605782a262..d8f2f46476 100644 --- a/mathesar_ui/src/pages/database/settings/collaborators/Collaborators.svelte +++ b/mathesar_ui/src/pages/database/settings/collaborators/Collaborators.svelte @@ -102,6 +102,7 @@ {$_('actions')} {#each collaboratorsList as collaborator (collaborator.id)} form.reset()}> - {$_('edit_role_for_collaborator_value', { - values: { - collaborator: userName, - }, - })} + + {#if slotName === 'userName'} + {userName} + {/if} +
diff --git a/mathesar_ui/src/pages/database/settings/collaborators/RemoveCollaboratorBody.svelte b/mathesar_ui/src/pages/database/settings/collaborators/RemoveCollaboratorBody.svelte new file mode 100644 index 0000000000..db7d7db946 --- /dev/null +++ b/mathesar_ui/src/pages/database/settings/collaborators/RemoveCollaboratorBody.svelte @@ -0,0 +1,36 @@ + + +
    +
  • + + {#if slotName === 'userName'} + {userName} + {:else if slotName === 'databaseName'} + {databaseName} + {/if} + +
  • +
  • + + {#if slotName === 'userName'} + {userName} + {/if} + +
  • +
  • + + {#if slotName === 'roleName'} + {roleName} + {/if} + +
  • +
diff --git a/mathesar_ui/src/pages/database/settings/collaborators/RemoveCollaboratorTitle.svelte b/mathesar_ui/src/pages/database/settings/collaborators/RemoveCollaboratorTitle.svelte new file mode 100644 index 0000000000..eef9f6c365 --- /dev/null +++ b/mathesar_ui/src/pages/database/settings/collaborators/RemoveCollaboratorTitle.svelte @@ -0,0 +1,20 @@ + + + + {#if slotName === 'userName'} + {userName} + {:else if slotName === 'databaseName'} + {databaseName} + {/if} + diff --git a/mathesar_ui/src/pages/database/settings/role-configuration/ConfigureRoleModal.svelte b/mathesar_ui/src/pages/database/settings/role-configuration/ConfigureRoleModal.svelte index 10d0b3b77a..ddb214b67e 100644 --- a/mathesar_ui/src/pages/database/settings/role-configuration/ConfigureRoleModal.svelte +++ b/mathesar_ui/src/pages/database/settings/role-configuration/ConfigureRoleModal.svelte @@ -8,7 +8,9 @@ requiredField, } from '@mathesar/components/form'; import Field from '@mathesar/components/form/Field.svelte'; + import Identifier from '@mathesar/components/Identifier.svelte'; import WarningBox from '@mathesar/components/message-boxes/WarningBox.svelte'; + import RichText from '@mathesar/components/rich-text/RichText.svelte'; import { type CombinedLoginRole, DatabaseSettingsRouteContext, @@ -43,9 +45,11 @@ form.reset()}> - {$_('configure_value', { - values: { value: combinedLoginRole.name }, - })} + + {#if slotName === 'role'} + {combinedLoginRole.name} + {/if} +
diff --git a/mathesar_ui/src/pages/database/settings/role-configuration/RoleConfiguration.svelte b/mathesar_ui/src/pages/database/settings/role-configuration/RoleConfiguration.svelte index 8b038f39ae..91b5d60929 100644 --- a/mathesar_ui/src/pages/database/settings/role-configuration/RoleConfiguration.svelte +++ b/mathesar_ui/src/pages/database/settings/role-configuration/RoleConfiguration.svelte @@ -5,15 +5,12 @@ import GridTableCell from '@mathesar/components/grid-table/GridTableCell.svelte'; import ErrorBox from '@mathesar/components/message-boxes/ErrorBox.svelte'; import PhraseContainingIdentifier from '@mathesar/components/PhraseContainingIdentifier.svelte'; + import Yes from '@mathesar/components/Yes.svelte'; import { type CombinedLoginRole, DatabaseSettingsRouteContext, } from '@mathesar/contexts/DatabaseSettingsRouteContext'; - import { - iconConfigurePassword, - iconDeleteMajor, - iconEdit, - } from '@mathesar/icons'; + import { iconAddNew, iconDeleteMajor, iconEdit } from '@mathesar/icons'; import AsyncRpcApiStore from '@mathesar/stores/AsyncRpcApiStore'; import { confirm } from '@mathesar/stores/confirmation'; import { modal } from '@mathesar/stores/modal'; @@ -68,7 +65,7 @@ - {$_('role_configuration')} + {$_('stored_role_passwords')} {#if isLoading} @@ -77,7 +74,7 @@
{$_('role')} - {$_('actions')} + {$_('stored_password')} {#each $combinedLoginRoles as combinedLoginRole (combinedLoginRole.name)} @@ -86,55 +83,64 @@ - {#if combinedLoginRole.configuredRole} +
+
+ {#if combinedLoginRole.configuredRole} + + {/if} +
- - - confirm({ - title: { - component: PhraseContainingIdentifier, - props: { - identifier: combinedLoginRole.name, - wrappingString: $_( - 'remove_configuration_for_identifier', - ), + {#if combinedLoginRole.configuredRole} + + + confirm({ + title: { + component: PhraseContainingIdentifier, + props: { + identifier: combinedLoginRole.name, + wrappingString: $_( + 'remove_stored_password_for_identifier', + ), + }, }, - }, - body: $_('removing_role_configuration_warning', { - values: { - server: - combinedLoginRole.configuredRole?.database.server.getConnectionString(), + body: $_('removing_role_configuration_warning', { + values: { + server: + combinedLoginRole.configuredRole?.database.server.getConnectionString(), + }, + }), + proceedButton: { + label: $_('remove_configuration'), + icon: iconDeleteMajor, }, - }), - proceedButton: { - label: $_('remove_configuration'), - icon: iconDeleteMajor, - }, - })} - label={$_('remove')} - onClick={() => removeConfiguredRole(combinedLoginRole)} - /> + })} + label="" + tooltip={$_('remove_stored_password')} + icon={iconDeleteMajor} + onClick={() => removeConfiguredRole(combinedLoginRole)} + /> + {:else if combinedLoginRole.role} + + {/if}
- {:else if combinedLoginRole.role} - - {/if} +
{/each}
@@ -164,10 +170,16 @@ diff --git a/mathesar_ui/src/pages/database/settings/roles/ModifyRoleMembers.svelte b/mathesar_ui/src/pages/database/settings/roles/ModifyRoleMembers.svelte index 1b02217d59..5d7dced35f 100644 --- a/mathesar_ui/src/pages/database/settings/roles/ModifyRoleMembers.svelte +++ b/mathesar_ui/src/pages/database/settings/roles/ModifyRoleMembers.svelte @@ -6,8 +6,10 @@ makeForm, requiredField, } from '@mathesar/components/form'; + import Identifier from '@mathesar/components/Identifier.svelte'; import InfoBox from '@mathesar/components/message-boxes/InfoBox.svelte'; import WarningBox from '@mathesar/components/message-boxes/WarningBox.svelte'; + import RichText from '@mathesar/components/rich-text/RichText.svelte'; import { iconDeleteMajor } from '@mathesar/icons'; import type { Role } from '@mathesar/models/Role'; import { toast } from '@mathesar/stores/toast'; @@ -60,11 +62,11 @@ form.reset()}> - {$_('edit_child_roles_for_parent', { - values: { - parent: parentRole.name, - }, - })} + + {#if slotName === 'parent'} + {parentRole.name} + {/if} +