diff --git a/mathesar_ui/src/api/rpc/databases.ts b/mathesar_ui/src/api/rpc/databases.ts index 16cee65a1c..e7c867c782 100644 --- a/mathesar_ui/src/api/rpc/databases.ts +++ b/mathesar_ui/src/api/rpc/databases.ts @@ -44,6 +44,8 @@ export interface RawDatabasePrivilegesForRole { direct: DatabasePrivilege[]; } +export type SystemSchema = 'msar' | '__msar' | 'mathesar_types'; + export const databases = { get: rpcMethodTypeContainer< { @@ -69,6 +71,11 @@ export const databases = { disconnect: rpcMethodTypeContainer< { database_id: RawDatabase['id']; + schemas_to_remove?: SystemSchema[]; + strict?: boolean; + role_name?: string; + password?: string; + disconnect_db_server?: boolean; }, void >(), diff --git a/mathesar_ui/src/component-library/button/Button.scss b/mathesar_ui/src/component-library/button/Button.scss index eaaacab2f6..0d9e3f624c 100644 --- a/mathesar_ui/src/component-library/button/Button.scss +++ b/mathesar_ui/src/component-library/button/Button.scss @@ -13,7 +13,6 @@ #000 0 0 0 0, #000 0 0 0 0, rgba(0, 0, 0, 0.05) 0 1px 2px 0; - font-weight: var(--font-weight-medium); position: relative; padding: var(--input-padding); box-sizing: border-box; diff --git a/mathesar_ui/src/component-library/fieldset/Fieldset.scss b/mathesar_ui/src/component-library/fieldset/Fieldset.scss index 067010fac0..3cca8c80fb 100644 --- a/mathesar_ui/src/component-library/fieldset/Fieldset.scss +++ b/mathesar_ui/src/component-library/fieldset/Fieldset.scss @@ -4,7 +4,6 @@ legend { padding: 0; - font-weight: var(--font-weight-medium); margin-bottom: 0.5rem; } legend:empty { diff --git a/mathesar_ui/src/component-library/labeled-input/LabeledInput.scss b/mathesar_ui/src/component-library/labeled-input/LabeledInput.scss index 7db9af8b01..215bd8c334 100644 --- a/mathesar_ui/src/component-library/labeled-input/LabeledInput.scss +++ b/mathesar_ui/src/component-library/labeled-input/LabeledInput.scss @@ -4,8 +4,6 @@ .label { display: inline-block; - color: var(--slate-800); - font-weight: var(--font-weight-medium); } .input { display: block; diff --git a/mathesar_ui/src/components/DocsLink.svelte b/mathesar_ui/src/components/DocsLink.svelte index 3582e372ae..c7e35ec10a 100644 --- a/mathesar_ui/src/components/DocsLink.svelte +++ b/mathesar_ui/src/components/DocsLink.svelte @@ -24,6 +24,8 @@ tablePermissions: '/user-guide/tables/#permissions', schemas: '/user-guide/schemas/', userAdmin: '/user-guide/users/#admin', + dataTypes: '/user-guide/data-types/', + metadata: '/user-guide/metadata/', }; type Page = keyof typeof pages; diff --git a/mathesar_ui/src/i18n/languages/en/dict.json b/mathesar_ui/src/i18n/languages/en/dict.json index 7cdfdfc4db..7571a8498f 100644 --- a/mathesar_ui/src/i18n/languages/en/dict.json +++ b/mathesar_ui/src/i18n/languages/en/dict.json @@ -173,6 +173,7 @@ "database_access_connect_help": "Can access the database", "database_access_create_help": "Can access the database and create new schemas", "database_disconnect_failed": "Unable to disconnect database", + "database_disconnect_form_into": "This will disconnect the database from Mathesar.", "database_disconnect_success": "The database has been disconnected successfully", "database_name": "Database Name", "database_new_items_scroll_hint": "Scroll or click here to see the database.", @@ -227,14 +228,17 @@ "disconnect_database_db_delete_info": "If you would like to delete the database too, you will need to do so from outside Mathesar by deleting it directly in PostgreSQL.", "disconnect_database_info": "The database will not be deleted and will still be accessible outside Mathesar. You may choose to reconnect to it in the future; however, upon disconnecting you will lose Mathesar-specific metadata such as saved explorations, customized column display options, and customized record summary templates.", "disconnect_database_with_name": "Disconnect Database [identifier]?", + "disconnect_named_database": "Disconnect [databaseName] Database", "display_language": "Display Language", "display_name": "Display Name", "documentation_and_resources": "Documentation & Resources", + "drop_not_yet_implemented": "Dropping databases from within Mathesar is not yet implemented. You can use PostgreSQL directly to drop the database if needed. See this [link](issue) for more information.", "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]?", + "drop_the_database": "Drop the database", "edit": "Edit", "edit_child_roles_for_parent": "Edit [parent] child roles", "edit_connection": "Edit Connection", @@ -323,6 +327,7 @@ "import": "Import", "import_from_file": "Import from a File", "in_mathesar": "In Mathesar", + "in_postgres": "In PostgreSQL", "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.", @@ -334,6 +339,7 @@ "join_community_chat": "Join Community Chat", "join_email_list": "Join Email List", "keep_first_row_as_data": "Set generic column names, keeping the first row as data", + "keep_the_database": "Keep the database", "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.", "last_checked": "Last checked", @@ -457,6 +463,7 @@ "open_table_record": "Open a Record from [tableName]", "operation_requires_pg_user_have_createdb": "This operation requires the \"{username}\" PostgreSQL user to have CREATEDB privileges.", "or": "or", + "outside_of_mathesar": "Outside of Mathesar", "overridden": "Overridden", "overview": "Overview", "owner": "Owner", @@ -545,11 +552,27 @@ "remove_configuration_for_identifier": "Remove Configuration for [identifier]?", "remove_filters": "{count, plural, one {Remove Filter} other {Remove {count} Filters}}", "remove_grouping": "Remove Grouping", + "remove_internal_schemas": "Remove Mathesar's internal schemas", + "remove_internal_schemas_help_1": "When checked, this will remove the \"msar\" and \"__msar\" schemas from the database.", + "remove_internal_schemas_help_2": "These schemas contain functions only necessary for the Mathesar application and can safely be deleted when disconnecting a database. You can easily reinstall them by reconnecting the database to Mathesar.", + "remove_internal_schemas_help_3": "See our [link](documentation) to learn more about Mathesar's internal schemas.", + "remove_metadata": "Remove saved explorations and other metadata", + "remove_metadata_field_help": "When disconnecting a database, Mathesar will delete all saved [explorationsLink](explorations) and other [metadataLink](metadata) such as custom column display options and record summary templates.", "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]?", "remove_stored_password_help": "Removing this stored password will prevent collaborators assigned to this role from accessing databases on server ''{server}''.", + "remove_stored_role_passwords": "Remove stored role passwords", + "remove_stored_role_passwords_help_1": "Because you are deleting the last database associated with its containing server, this option is present.", + "remove_stored_role_passwords_help_checked": "With this box [bold](checked), the passwords that you've stored for PostgreSQL roles on this database's server will be deleted from Mathesar's internal database.", + "remove_stored_role_passwords_help_unchecked": "With this box [bold](unchecked), the passwords will remain in Mathesar's internal database, but you will not have a way to edit them or remove them unless you re-connect another database associated with the same server.", + "remove_types_schema": "Remove Mathesar's custom data types", + "remove_types_schema_help_1": "When checked, this will attempt to remove the \"mathesar_types\" schema from the database.", + "remove_types_schema_help_2": "This schema contains custom PostgreSQL data types that Mathesar uses for Email, Money, and URL types.", + "remove_types_schema_help_3": "If you have any data using these types, and you attempt to remove the types by checking this box, then the entire process of disconnecting the database will fail with an error. In this case, all your data will be preserved and no changes will be made.", + "remove_types_schema_help_4": "You can safely leave these types in your database if you so choose.", + "remove_types_schema_help_5": "See our [link](documentation) to learn more about Mathesar data types.", "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", @@ -616,6 +639,7 @@ "seconds": "Seconds", "section_affects_database_config": "This section affects the configuration of the database.", "section_affects_postgresql_config": "The configuration in this section is stored within the connected PostgreSQL database.", + "see_docs_for_stored_role_password_help": "See our [docsLink](documentation) for more information on stored role passwords.", "see_docs_to_learn_more": "See our [link](documentation) to learn more.", "see_whats_shared": "See what's shared.", "select_cell_view_properties": "Select a cell to view it's properties.", @@ -715,6 +739,7 @@ "the_credentials_will_be_copied_from_this_connection": "The username, password, host, and port will be copied from this connection.", "the_errors_are_shown_below_for_each_database": "The errors are shown below for each database.", "the_following_databases_will_be_upgraded": "The following databases will be upgraded:", + "this_behavior_is_not_configurable": "This behavior is not configurable.", "this_will_remove_following_columns": "This will remove the following column(s):", "this_will_remove_following_transformations": "This will remove the following transformation(s):", "time_to_create_exploration": "It's time to use your tables. Create your first exploration.", @@ -773,6 +798,8 @@ "use_custom_template": "Use Custom Template", "use_default": "Use Default", "use_existing_pg_user": "Use an existing PostgreSQL user", + "use_role_to_remove_schemas": "Specify a role to use when removing schemas", + "use_role_to_remove_schemas_help": "If your Mathesar internal schemas require extra privileges to remove, you may specify a role to use here. This role and password will not be stored in Mathesar.", "use_text_for_all_columns": "Use \"Text\" for all column data types", "user": "User", "user_name": "User name", diff --git a/mathesar_ui/src/pages/database/DatabasePageWrapper.svelte b/mathesar_ui/src/pages/database/DatabasePageWrapper.svelte index fad8b66852..b75a08e3f1 100644 --- a/mathesar_ui/src/pages/database/DatabasePageWrapper.svelte +++ b/mathesar_ui/src/pages/database/DatabasePageWrapper.svelte @@ -3,7 +3,6 @@ import { router } from 'tinro'; import AppSecondaryHeader from '@mathesar/components/AppSecondaryHeader.svelte'; - import PhraseContainingIdentifier from '@mathesar/components/PhraseContainingIdentifier.svelte'; import SeeDocsToLearnMore from '@mathesar/components/SeeDocsToLearnMore.svelte'; import { DatabaseRouteContext } from '@mathesar/contexts/DatabaseRouteContext'; import { @@ -20,10 +19,8 @@ getDatabasePageSchemasSectionUrl, getDatabasePageSettingsSectionUrl, } from '@mathesar/routes/urls'; - import { confirm } from '@mathesar/stores/confirmation'; import { databasesStore } from '@mathesar/stores/databases'; import { modal } from '@mathesar/stores/modal'; - import { toast } from '@mathesar/stores/toast'; import { getUserProfileStoreFromContext } from '@mathesar/stores/userProfile'; import UpgradeDatabaseModal from '@mathesar/systems/databases/upgrade-database/UpgradeDatabaseModal.svelte'; import { preloadCommonData } from '@mathesar/utils/preloadData'; @@ -36,6 +33,7 @@ TabContainer, } from '@mathesar-component-library'; + import DisconnectDatabaseModal from './disconnect/DisconnectDatabaseModal.svelte'; import DatabasePermissionsModal from './permissions/DatabasePermissionsModal.svelte'; const databaseRouteContext = DatabaseRouteContext.get(); @@ -51,6 +49,7 @@ database.server.port === commonData.internal_db.port; const permissionsModal = modal.spawnModalController(); + const disconnectModal = modal.spawnModalController(); const reinstallModal = modal.spawnModalController(); const userProfileStore = getUserProfileStoreFromContext(); @@ -76,39 +75,6 @@ export function setSection(_section: Section) { section = _section; } - - async function disconnectDatabase() { - await confirm({ - title: { - component: PhraseContainingIdentifier, - props: { - identifier: database.name, - wrappingString: $_('disconnect_database_with_name'), - }, - }, - body: [ - $_('action_cannot_be_undone'), - $_('disconnect_database_info'), - $_('disconnect_database_db_delete_info'), - $_('are_you_sure_to_proceed'), - ], - proceedButton: { - label: $_('disconnect_database'), - icon: undefined, - }, - onProceed: async () => { - await databasesStore.disconnectDatabase(database); - }, - onSuccess: () => { - toast.success($_('database_disconnect_success')); - router.goto('/'); - }, - onError: (e) => - toast.error({ - message: `${$_('database_disconnect_failed')} ${e.message}`, - }), - }); - } @@ -145,7 +111,10 @@ icon={iconMoreActions} preferredPlacement="bottom-end" > - + disconnectModal.open(database)} + > {$_('disconnect_database')} + { + await databasesStore.disconnectDatabase(opts); + router.goto('/'); + }} +/> diff --git a/mathesar_ui/src/pages/database/disconnect/DisconnectDatabaseModal.svelte b/mathesar_ui/src/pages/database/disconnect/DisconnectDatabaseModal.svelte new file mode 100644 index 0000000000..1ac66c515f --- /dev/null +++ b/mathesar_ui/src/pages/database/disconnect/DisconnectDatabaseModal.svelte @@ -0,0 +1,31 @@ + + + + + + {#if slotName === 'databaseName'} + {database.name} + {/if} + + + controller.close()} + /> + diff --git a/mathesar_ui/src/stores/databases.ts b/mathesar_ui/src/stores/databases.ts index a215276bce..d4e38de15b 100644 --- a/mathesar_ui/src/stores/databases.ts +++ b/mathesar_ui/src/stores/databases.ts @@ -2,7 +2,7 @@ import { map } from 'iter-tools'; import { type Readable, derived, writable } from 'svelte/store'; import { api } from '@mathesar/api/rpc'; -import type { RawDatabase } from '@mathesar/api/rpc/databases'; +import type { RawDatabase, SystemSchema } from '@mathesar/api/rpc/databases'; import type { RawServer } from '@mathesar/api/rpc/servers'; import { Database } from '@mathesar/models/Database'; import { Server } from '@mathesar/models/Server'; @@ -98,13 +98,23 @@ class DatabasesStore { return connectedDatabase; } - async disconnectDatabase(database: Database) { + async disconnectDatabase(p: { + database: Pick; + schemas_to_remove?: SystemSchema[]; + role?: { name: string; password: string }; + disconnect_db_server: boolean; + }) { await api.databases.configured .disconnect({ - database_id: database.id, + database_id: p.database.id, + strict: true, + schemas_to_remove: p.schemas_to_remove, + role_name: p.role?.name, + password: p.role?.password, + disconnect_db_server: p.disconnect_db_server, }) .run(); - this.unsortedDatabases.delete(database.id); + this.unsortedDatabases.delete(p.database.id); } async refresh() { @@ -125,6 +135,8 @@ class DatabasesStore { } } +export type DatabaseDisconnectFn = typeof databasesStore.disconnectDatabase; + export const databasesStore: MakeWritablePropertiesReadable = new DatabasesStore( generateDatabaseEntries(commonData.servers, commonData.databases), diff --git a/mathesar_ui/src/systems/table-view/table-inspector/column/ColumnNameAndDescription.svelte b/mathesar_ui/src/systems/table-view/table-inspector/column/ColumnNameAndDescription.svelte index cc938b6b0b..243c3fc020 100644 --- a/mathesar_ui/src/systems/table-view/table-inspector/column/ColumnNameAndDescription.svelte +++ b/mathesar_ui/src/systems/table-view/table-inspector/column/ColumnNameAndDescription.svelte @@ -79,7 +79,4 @@ margin-top: 0.25rem; } } - .label { - font-weight: var(--font-weight-medium); - } diff --git a/mathesar_ui/src/systems/table-view/table-inspector/table/TableDescription.svelte b/mathesar_ui/src/systems/table-view/table-inspector/table/TableDescription.svelte index 61c74f7887..9278287da8 100644 --- a/mathesar_ui/src/systems/table-view/table-inspector/table/TableDescription.svelte +++ b/mathesar_ui/src/systems/table-view/table-inspector/table/TableDescription.svelte @@ -38,7 +38,4 @@ margin-top: 0.25rem; } } - .label { - font-weight: var(--font-weight-medium); - } diff --git a/mathesar_ui/src/systems/table-view/table-inspector/table/TableName.svelte b/mathesar_ui/src/systems/table-view/table-inspector/table/TableName.svelte index da1bb23880..1464840d2c 100644 --- a/mathesar_ui/src/systems/table-view/table-inspector/table/TableName.svelte +++ b/mathesar_ui/src/systems/table-view/table-inspector/table/TableName.svelte @@ -45,7 +45,4 @@ margin-top: 0.25rem; } } - .label { - font-weight: var(--font-weight-medium); - }