Skip to content

Commit 9b10aba

Browse files
authored
Merge pull request #3810 from mathesar-foundation/db-page-3
Database permissions modal - 'Share' tab
2 parents eb2b597 + 72a7838 commit 9b10aba

32 files changed

+1095
-66
lines changed

mathesar/urls.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,19 @@
5252
path('profile/', views.profile, name='profile'),
5353
path('administration/', views.admin_home, name='admin_home'),
5454
path('administration/users/', views.admin_home, name='admin_users_home'),
55-
path('administration/users/<user_id>/', views.admin_home, name='admin_users_edit'),
55+
path('administration/users/<int:user_id>/', views.admin_home, name='admin_users_edit'),
5656
path('administration/update/', views.admin_home, name='admin_update'),
5757
path('shares/tables/<slug>/', views.shared_table, name='shared_table'),
5858
path('shares/explorations/<slug>/', views.shared_query, name='shared_query'),
5959
path('databases/', views.databases, name='databases'),
6060
path('i18n/', include('django.conf.urls.i18n')),
6161
re_path(
62-
r'^db/(?P<database_id>\w+)/schemas/(?P<schema_id>\w+)/',
62+
r'^db/(?P<database_id>\d+)/schemas/(?P<schema_id>\d+)/',
6363
views.schemas_home,
6464
name='schema_home'
6565
),
6666
re_path(
67-
r'^db/(?P<database_id>\w+)/((schemas|settings)/)?',
67+
r'^db/(?P<database_id>\d+)/((schemas|settings)/)?',
6868
views.schemas,
6969
name='schemas'
7070
),

mathesar/views.py

+14-7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from mathesar.rpc.databases.configured import list_ as databases_list
1111
from mathesar.rpc.schemas import list_ as schemas_list
1212
from mathesar.rpc.servers.configured import list_ as get_servers_list
13+
from mathesar.rpc.tables import list_with_metadata as tables_list
1314
from mathesar.api.serializers.databases import TypeSerializer
1415
from mathesar.api.serializers.tables import TableSerializer
1516
from mathesar.api.serializers.queries import QuerySerializer
@@ -33,13 +34,19 @@ def get_database_list(request):
3334
return databases_list(request=request)
3435

3536

36-
def get_table_list(request, schema_id):
37-
# TODO: Fill this method
38-
return []
37+
def get_table_list(request, database_id, schema_oid):
38+
if database_id is not None and schema_oid is not None:
39+
return tables_list(
40+
request=request,
41+
database_id=database_id,
42+
schema_oid=schema_oid
43+
)
44+
else:
45+
return []
3946

4047

4148
def get_queries_list(request, schema_id):
42-
# TODO: Fill this method
49+
# TODO_BETA: Fill this method
4350
return []
4451

4552

@@ -80,8 +87,8 @@ def _get_internal_db_meta():
8087
def _get_base_data_all_routes(request, database_id=None, schema_id=None):
8188
return {
8289
'abstract_types': get_ui_type_list(request, database_id),
83-
'current_database': database_id,
84-
'current_schema': schema_id,
90+
'current_database': int(database_id) if database_id else None,
91+
'current_schema': int(schema_id) if schema_id else None,
8592
'current_release_tag_name': __version__,
8693
'databases': get_database_list(request),
8794
'servers': get_servers_list(),
@@ -98,7 +105,7 @@ def _get_base_data_all_routes(request, database_id=None, schema_id=None):
98105
def get_common_data(request, database_id=None, schema_id=None):
99106
return {
100107
**_get_base_data_all_routes(request, database_id, schema_id),
101-
'tables': get_table_list(request, schema_id),
108+
'tables': get_table_list(request, database_id, schema_id),
102109
'queries': get_queries_list(request, schema_id),
103110
'routing_context': 'normal',
104111
}

mathesar_ui/src/api/rpc/databases.ts

+42-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { rpcMethodTypeContainer } from '@mathesar/packages/json-rpc-client-builder';
22

3-
import type { RawConfiguredRole } from './roles';
3+
import type { RawConfiguredRole, RawRole } from './roles';
44
import type { RawServer } from './servers';
55

66
export interface RawDatabase {
@@ -9,6 +9,21 @@ export interface RawDatabase {
99
server_id: RawServer['id'];
1010
}
1111

12+
export const allDatabasePrivileges = [
13+
'CREATE',
14+
'CONNECT',
15+
'TEMPORARY',
16+
] as const;
17+
export type DatabasePrivilege = (typeof allDatabasePrivileges)[number];
18+
19+
export interface RawUnderlyingDatabase {
20+
oid: number;
21+
name: string;
22+
owner_oid: RawRole['oid'];
23+
current_role_priv: DatabasePrivilege[];
24+
current_role_owns: boolean;
25+
}
26+
1227
export const sampleDataOptions = [
1328
'library_management',
1429
'movie_collection',
@@ -22,7 +37,18 @@ export interface DatabaseConnectionResult {
2237
configured_role: RawConfiguredRole;
2338
}
2439

40+
export interface RawDatabasePrivilegesForRole {
41+
role_oid: RawRole['oid'];
42+
direct: DatabasePrivilege[];
43+
}
44+
2545
export const databases = {
46+
get: rpcMethodTypeContainer<
47+
{
48+
database_id: RawDatabase['id'];
49+
},
50+
RawUnderlyingDatabase
51+
>(),
2652
configured: {
2753
list: rpcMethodTypeContainer<
2854
{
@@ -51,4 +77,19 @@ export const databases = {
5177
DatabaseConnectionResult
5278
>(),
5379
},
80+
privileges: {
81+
list_direct: rpcMethodTypeContainer<
82+
{
83+
database_id: RawDatabase['id'];
84+
},
85+
Array<RawDatabasePrivilegesForRole>
86+
>(),
87+
replace_for_roles: rpcMethodTypeContainer<
88+
{
89+
database_id: RawDatabase['id'];
90+
privileges: Array<RawDatabasePrivilegesForRole>;
91+
},
92+
Array<RawDatabasePrivilegesForRole>
93+
>(),
94+
},
5495
};

mathesar_ui/src/component-library/checkbox-group/CheckboxGroup.svelte

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts">
2-
import type { SvelteComponent } from 'svelte';
2+
import { type SvelteComponent, createEventDispatcher } from 'svelte';
33
44
import Checkbox from '@mathesar-component-library-dir/checkbox/Checkbox.svelte';
55
import type { LabelGetter } from '@mathesar-component-library-dir/common/utils/formatUtils';
@@ -9,6 +9,10 @@
99
1010
type Option = $$Generic;
1111
12+
const dispatch = createEventDispatcher<{
13+
artificialChange: Option[];
14+
}>();
15+
1216
export let values: Option[] = [];
1317
export let isInline = false;
1418
export let options: readonly Option[] = [];
@@ -44,6 +48,7 @@
4448
} else {
4549
values = values.filter((value) => !valuesAreEqual(value, option));
4650
}
51+
dispatch('artificialChange', values);
4752
}
4853
</script>
4954

mathesar_ui/src/component-library/collapsible/Collapsible.scss

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
text-align: left;
1212
cursor: pointer;
1313
font-weight: inherit;
14+
padding: var(--Collapsible_trigger-padding, 0.5em);
1415
.collapsible-header-title {
1516
flex-grow: 1;
1617
overflow: hidden;
17-
font-weight: 600;
18+
font-weight: var(--Collapsible_header-font-weight, 600);
1819
}
1920
svg {
2021
flex-shrink: 0;

mathesar_ui/src/component-library/common/utils/ImmutableSet.ts

+4
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ export default class ImmutableSet<T> {
5454
return this.set.has(item);
5555
}
5656

57+
equals(other: Iterable<T> & { size: number }): boolean {
58+
return this.size === other.size && this.union(other).size === this.size;
59+
}
60+
5761
get size(): number {
5862
return this.set.size;
5963
}

mathesar_ui/src/component-library/dropdown/Dropdown.scss

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ button.dropdown.trigger {
99
text-overflow: ellipsis;
1010
white-space: nowrap;
1111
box-sizing: content-box;
12-
line-height: 1.2;
13-
min-height: 1.2em;
12+
line-height: 1;
13+
min-height: 1em;
1414
flex-grow: 1;
1515
> *:not(:last-child) {
1616
margin-right: 0.25rem;

mathesar_ui/src/component-library/select/Select.svelte

+3-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@
163163
on:blur
164164
>
165165
<svelte:fragment slot="trigger">
166-
{#if $$slots.default}
166+
{#if $$slots.trigger}
167+
<slot name="trigger" option={value} label={getLabel(value)} />
168+
{:else if $$slots.default}
167169
<slot option={value} label={getLabel(value)} />
168170
{:else}
169171
<StringOrComponent arg={getLabel(value)} />

mathesar_ui/src/component-library/tabs/TabContainer.scss

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
border-radius: 2px 2px 0px 0px;
2626
border-bottom: 2px solid transparent;
2727
margin-bottom: -1px;
28-
margin-right: 2rem;
28+
margin-right: var(--Tab_margin-right, 2rem);
2929
font-size: var(--text-size-large);
3030

3131
> div,
@@ -113,7 +113,7 @@
113113
> li.tab {
114114
font-size: var(--text-size-base);
115115
text-align: center;
116-
margin-right: 0;
116+
margin-right: var(--Tab_margin-right, 0);
117117
> div {
118118
padding: 0.5rem 0;
119119
}

mathesar_ui/src/contexts/DatabaseRouteContext.ts

+3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ export class DatabaseRouteContext {
1010

1111
roles;
1212

13+
underlyingDatabase;
14+
1315
constructor(database: Database) {
1416
this.database = database;
1517
this.roles = database.constructRolesStore();
18+
this.underlyingDatabase = database.constructUnderlyingDatabaseStore();
1619
}
1720

1821
/**

mathesar_ui/src/i18n/languages/en/dict.json

+16
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
{
2+
"access_custom_help": "Custom permissions",
3+
"access_for_roles_saved_successfully": "Access for roles have been saved successfully.",
24
"access_level_cannot_remove_warning": "This access level cannot be removed.",
35
"access_level_inheritance_help": "This access level is inherited from the {aclObject} permissions.",
46
"access_level_inheritance_is_overridden_help": "This access level is inherited from the {aclObject} permissions and is overridden by the {comparedAclObject} permissions.",
57
"access_level_is_overridden_help": "This access level is overridden by the {comparedAclObject} permissions.",
68
"access_level_overrides_help": "This access level overrides the {comparedAclObject} permissions.",
79
"access_level_precedence_help": "If a user has different access levels on the database and the schema, the access level of schema will take precedence.",
10+
"access_not_granted_for_any_role": "Access has not been granted for any role.",
811
"account_details": "Account Details",
912
"action_cannot_be_undone": "This action cannot be undone",
1013
"actions": "Actions",
@@ -16,6 +19,7 @@
1619
"add_new_filter": "Add New Filter",
1720
"add_new_grouping": "Add New Grouping",
1821
"add_new_sort_condition": "Add new sort condition",
22+
"add_roles": "Add Role(s)",
1923
"add_tables_to_new_schema": "You've created a new schema, now add tables to it.",
2024
"add_transformation_step": "Add transformation step",
2125
"add_user": "Add User",
@@ -49,6 +53,7 @@
4953
"change_password": "Change Password",
5054
"check_for_updates": "Check for Updates",
5155
"child_roles": "Child Roles",
56+
"child_roles_count": "{count, plural, one {{count} child role} other {{count} child roles}}",
5257
"child_roles_saved_successfully": "The Child Roles have been successfully saved.",
5358
"choose_database": "Choose a Database",
5459
"choose_schema": "Choose a Schema",
@@ -91,6 +96,7 @@
9196
"confirm_and_create_table": "Confirm & create table",
9297
"confirm_delete_table": "To confirm the deletion of the [tableName] table, please enter the table name into the input field below.",
9398
"confirm_password": "Confirm Password",
99+
"connect": "Connect",
94100
"connect_database": "Connect Database",
95101
"connect_existing_database": "Connect to an Existing Database",
96102
"connect_with_community_help": "Connect with Mathesar users and contributors in our community chat. Share ideas, get help, and contribute to discussions.",
@@ -117,6 +123,7 @@
117123
"count_new_records": "{count, plural, one {{count} new record} other {{count} new records}}",
118124
"count_records_deleted_successfully": "{count, plural, one {{count} record deleted successfully!} other {{count} records deleted successfully!}}",
119125
"count_tables": "{count, plural, one {{count} table} other {{count} tables}}",
126+
"create": "Create",
120127
"create_a_table_by_importing": "Create a table by importing your data",
121128
"create_database": "Create Database",
122129
"create_database_mathesar_internal_server": "Create a new PostgreSQL database on Mathesar's internal server",
@@ -144,9 +151,14 @@
144151
"data_type_linked_column_restricted": "The data type of this column must match the referenced column and cannot be changed.",
145152
"data_type_pk_column_restricted": "The data type of the primary key column is restricted and cannot be changed.",
146153
"database": "Database",
154+
"database_access_connect_help": "Can access the database",
155+
"database_access_create_help": "Can access the database and create new schemas",
147156
"database_name": "Database Name",
148157
"database_not_found": "Database with id [connectionId] is not found.",
149158
"database_permissions": "Database Permissions",
159+
"database_privilege_connect_help": "Allow connections to the database.",
160+
"database_privilege_create_help": "Allow creation of new schemas.",
161+
"database_privilege_temporary_help": "Allow creation of temporary tables.",
150162
"database_server_credentials": "Database server credentials",
151163
"database_type": "Database Type",
152164
"databases": "Databases",
@@ -258,6 +270,7 @@
258270
"go_to_record": "Go To Record",
259271
"go_to_record_page": "Go to Record Page",
260272
"go_to_record_with_value": "Go To Record {value}",
273+
"granted_access": "Granted Access",
261274
"group": "Group",
262275
"group_by_column": "Group by Column",
263276
"group_records_by": "Group records by",
@@ -397,6 +410,7 @@
397410
"or": "or",
398411
"overridden": "Overridden",
399412
"overview": "Overview",
413+
"owner": "Owner",
400414
"page_automatic_reload_update": "This page will automatically reload, showing the software update status again.",
401415
"page_doesnt_exist": "The page you're looking for doesn't exist.",
402416
"password": "Password",
@@ -469,6 +483,7 @@
469483
"role_dropped_successfully": "The Role has been dropped successfully",
470484
"role_has_no_child_roles": "The Role does not have any Child Roles",
471485
"role_name": "Role Name",
486+
"role_permissions": "Role Permissions",
472487
"roles": "Roles",
473488
"row": "Row",
474489
"running_latest_version": "You are running the latest version",
@@ -569,6 +584,7 @@
569584
"this_will_remove_following_transformations": "This will remove the following transformation(s):",
570585
"time_to_create_exploration": "It's time to use your tables. Create your first exploration.",
571586
"today": "Today",
587+
"transfer_ownership": "Transfer Ownership",
572588
"transform_results": "Transform Results",
573589
"transform_results_help": "Transformations can be used to summarize data, filter data, and more. Note that transformations are applied in the order they are listed.",
574590
"two_columns_cannot_have_same_name": "The two columns cannot have the same name.",

mathesar_ui/src/icons/customIcons.ts

+12
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,15 @@ export const connectDatabaseIcon: IconProps['data'] = {
121121
],
122122
],
123123
};
124+
125+
export const treeChildNodeArrowIcon: IconProps['data'] = {
126+
icon: [
127+
9,
128+
10,
129+
[],
130+
'',
131+
[
132+
'M0.5 5V0H1.5V5C1.5 6.933 3.067 8.5 5 8.5H9V9.5H5C2.51472 9.5 0.5 7.48528 0.5 5Z',
133+
],
134+
],
135+
};

mathesar_ui/src/icons/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ import {
8383
explorationIcon,
8484
outcomeIcon,
8585
tableIcon,
86+
treeChildNodeArrowIcon,
8687
} from './customIcons';
8788

8889
/**
@@ -178,6 +179,9 @@ export const iconTable: IconProps = { data: tableIcon };
178179
export const iconInspector: IconProps = { data: faInfo };
179180
export const iconTableLink: IconProps = { data: faLink };
180181
export const iconTechnicalExplanation: IconProps = { data: faHammer };
182+
export const iconTreeChildNodeArrow: IconProps = {
183+
data: treeChildNodeArrowIcon,
184+
};
181185
export const iconUpgradeAvailable: IconProps = { data: faCircleInfo };
182186
export const iconCurrentlyInstalledVersion: IconProps = { data: faCheck };
183187
export const iconUser: IconProps = { data: faUser };

mathesar_ui/src/models/Database.ts

+16
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,22 @@ export class Database {
6363
});
6464
}
6565

66+
constructDatabasePrivilegesStore() {
67+
return new AsyncRpcApiStore(api.databases.privileges.list_direct, {
68+
postProcess: (rawDbPrivilegesForRoles) =>
69+
new ImmutableMap(
70+
rawDbPrivilegesForRoles.map((rawDatabasePrivilegesForRole) => [
71+
rawDatabasePrivilegesForRole.role_oid,
72+
rawDatabasePrivilegesForRole,
73+
]),
74+
),
75+
});
76+
}
77+
78+
constructUnderlyingDatabaseStore() {
79+
return new AsyncRpcApiStore(api.databases.get);
80+
}
81+
6682
addCollaborator(
6783
userId: number,
6884
configuredRoleId: ConfiguredRole['id'],

0 commit comments

Comments
 (0)