Skip to content

Commit

Permalink
Merge branch 'develop' into rd_db_dis_d
Browse files Browse the repository at this point in the history
  • Loading branch information
pavish authored Sep 23, 2024
2 parents 9cc36f9 + a77c6c8 commit 8d0d01b
Show file tree
Hide file tree
Showing 29 changed files with 597 additions and 179 deletions.
7 changes: 7 additions & 0 deletions mathesar_ui/src/api/rpc/databases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,12 @@ export const databases = {
},
Array<RawDatabasePrivilegesForRole>
>(),
transfer_ownership: rpcMethodTypeContainer<
{
database_id: RawDatabase['id'];
new_owner_oid: RawRole['oid'];
},
RawUnderlyingDatabase
>(),
},
};
10 changes: 10 additions & 0 deletions mathesar_ui/src/api/rpc/roles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ export const roles = {
RawRole
>(),

get_current_role: rpcMethodTypeContainer<
{
database_id: RawDatabase['id'];
},
{
current_role: RawRole;
parent_roles: RawRole[];
}
>(),

delete: rpcMethodTypeContainer<
{
database_id: RawDatabase['id'];
Expand Down
9 changes: 9 additions & 0 deletions mathesar_ui/src/api/rpc/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,14 @@ export const schemas = {
},
Array<RawSchemaPrivilegesForRole>
>(),

transfer_ownership: rpcMethodTypeContainer<
{
database_id: RawDatabase['id'];
schema_oid: RawSchema['oid'];
new_owner_oid: RawRole['oid'];
},
RawSchema
>(),
},
};
9 changes: 9 additions & 0 deletions mathesar_ui/src/api/rpc/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,5 +244,14 @@ export const tables = {
},
Array<RawTablePrivilegesForRole>
>(),

transfer_ownership: rpcMethodTypeContainer<
{
database_id: RawDatabase['id'];
table_oid: RawTable['oid'];
new_owner_oid: RawRole['oid'];
},
RawTable
>(),
},
};
5 changes: 5 additions & 0 deletions mathesar_ui/src/component-library/list-box/ListBox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
&.in-focus {
background: #f3f4f5;
}

&.disabled {
color: var(--slate-300);
cursor: not-allowed;
}
}

&.multiple {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@
{@const isSelected = $value.some((opt) =>
$staticProps.checkEquality(opt, option),
)}
{@const isDisabled = $staticProps.checkIfOptionIsDisabled(option)}
<li
role="option"
class:selected={isSelected}
class:disabled={isDisabled}
class:in-focus={index === $focusedOptionIndex}
aria-selected={isSelected ? true : undefined}
on:click={() => api.pick(option)}
Expand Down
6 changes: 5 additions & 1 deletion mathesar_ui/src/component-library/select/Select.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,13 @@
*/
export let valuesAreEqual: DefinedProps['valuesAreEqual'] = (a, b) => a === b;
export let isOptionDisabled: DefinedProps['isOptionDisabled'] = () => false;
export let autoSelect: DefinedProps['autoSelect'] = 'first';
function setValueFromArray(values: readonly (Option | undefined)[]) {
[value] = values;
const firstEnabledOption = values.find((opt) => !isOptionDisabled(opt));
value = firstEnabledOption;
dispatch('change', value);
dispatch('input', value);
dispatch('artificialChange', value);
Expand Down Expand Up @@ -140,6 +143,7 @@
{labelKey}
{getLabel}
checkEquality={valuesAreEqual}
checkIfOptionIsDisabled={isOptionDisabled}
let:api
let:isOpen
>
Expand Down
3 changes: 3 additions & 0 deletions mathesar_ui/src/component-library/select/SelectTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export interface SelectProps<Option> extends BaseInputProps {
triggerAppearance?: Appearance;
ariaLabel?: string;
valuesAreEqual?: ListBoxProps<Option | undefined>['checkEquality'];
isOptionDisabled?: ListBoxProps<
Option | undefined
>['checkIfOptionIsDisabled'];
/**
* When options change and the selected value is either undefined or
* not present in the options array, autoSelect determines how to
Expand Down
3 changes: 3 additions & 0 deletions mathesar_ui/src/contexts/DatabaseRouteContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ export class DatabaseRouteContext {

underlyingDatabase;

currentRole;

constructor(database: Database) {
this.database = database;
this.roles = database.constructRolesStore();
this.underlyingDatabase = database.constructUnderlyingDatabaseStore();
this.currentRole = database.constructCurrentRoleStore();
}

/**
Expand Down
4 changes: 4 additions & 0 deletions mathesar_ui/src/i18n/languages/en/dict.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
"database_access_create_help": "Can access the database and create new schemas",
"database_name": "Database Name",
"database_not_found": "Database with id [connectionId] is not found.",
"database_ownership_updated_successfully": "Database ownership has been updated successfully.",
"database_permissions": "Database Permissions",
"database_privilege_connect_help": "Allow connections to the database.",
"database_privilege_create_help": "Allow creation of new schemas.",
Expand Down Expand Up @@ -353,6 +354,7 @@
"new_column_added_to_table": "A new column will be added to [tableName]",
"new_foreign_key_constraint": "New Foreign Key Constraint",
"new_link_wont_work_once_regenerated": "Once you regenerate a new link, the old link will no longer work.",
"new_owner": "New Owner",
"new_password": "New Password",
"new_pg_user_privileges_help": "The user will be granted CONNECT and CREATE privileges on the database.",
"new_record": "New Record",
Expand Down Expand Up @@ -503,6 +505,7 @@
"schema_name_already_exists": "A schema with that name already exists.",
"schema_name_cannot_be_empty": "Schema name cannot be empty",
"schema_not_found": "Schema not found.",
"schema_ownership_updated_successfully": "Schema ownership has been updated successfully.",
"schema_permissions": "Schema Permissions",
"schema_privilege_create_help": "Allow creation of objects within the schema.",
"schema_privilege_usage_help": "Allow usage of the schema.",
Expand Down Expand Up @@ -575,6 +578,7 @@
"table_name_cannot_be_empty": "The table name cannot be empty.",
"table_not_found": "Table not found.",
"table_not_shared": "This table is currently not shared.",
"table_ownership_updated_successfully": "Table ownership has been updated successfully.",
"table_permissions": "Table Permissions",
"table_preview": "Table Preview",
"table_privilege_delete_help": "Allow deletion of records within the table.",
Expand Down
18 changes: 17 additions & 1 deletion mathesar_ui/src/models/Database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Collaborator } from './Collaborator';
import { ConfiguredRole } from './ConfiguredRole';
import { Role } from './Role';
import type { Server } from './Server';
import { UnderlyingDatabase } from './UnderlyingDatabase';

export class Database {
readonly id: number;
Expand Down Expand Up @@ -76,7 +77,22 @@ export class Database {
}

constructUnderlyingDatabaseStore() {
return new AsyncRpcApiStore(api.databases.get);
return new AsyncRpcApiStore(api.databases.get, {
postProcess: (rawUnderlyingDatabase) =>
new UnderlyingDatabase({
database: this,
rawUnderlyingDatabase,
}),
});
}

constructCurrentRoleStore() {
return new AsyncRpcApiStore(api.roles.get_current_role, {
postProcess: (currentRole) => ({
currentRoleOid: currentRole.current_role.oid,
parentRoleOids: currentRole.parent_roles.map((pr) => pr.oid),
}),
});
}

addCollaborator(
Expand Down
36 changes: 27 additions & 9 deletions mathesar_ui/src/models/Schema.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { type Readable, derived, writable } from 'svelte/store';

import { api } from '@mathesar/api/rpc';
import type { RawSchema, SchemaPrivilege } from '@mathesar/api/rpc/schemas';
import type { RawSchema } from '@mathesar/api/rpc/schemas';
import AsyncRpcApiStore from '@mathesar/stores/AsyncRpcApiStore';
import { CancellablePromise, ImmutableMap } from '@mathesar-component-library';

import type { Database } from './Database';
import { ObjectCurrentAccess } from './internal/ObjectCurrentAccess';
import type { Role } from './Role';

export class Schema {
readonly oid: number;
Expand All @@ -28,11 +30,7 @@ export class Schema {
return this._tableCount;
}

readonly owner_oid: number;

readonly current_role_priv: SchemaPrivilege[];

readonly current_role_owns: boolean;
readonly currentAccess;

readonly isPublicSchema;

Expand All @@ -44,9 +42,7 @@ export class Schema {
this.isPublicSchema = derived(this._name, ($name) => $name === 'public');
this._description = writable(props.rawSchema.description);
this._tableCount = writable(props.rawSchema.table_count);
this.owner_oid = props.rawSchema.owner_oid;
this.current_role_priv = props.rawSchema.current_role_priv;
this.current_role_owns = props.rawSchema.current_role_owns;
this.currentAccess = new ObjectCurrentAccess(props.rawSchema);
this.database = props.database;
}

Expand Down Expand Up @@ -76,6 +72,28 @@ export class Schema {
);
}

updateOwner(newOwner: Role['oid']) {
const promise = api.schemas.privileges
.transfer_ownership({
database_id: this.database.id,
schema_oid: this.oid,
new_owner_oid: newOwner,
})
.run();

return new CancellablePromise(
(resolve, reject) => {
promise
.then((result) => {
this.currentAccess.set(result);
return resolve(this);
}, reject)
.catch(reject);
},
() => promise.cancel(),
);
}

setTableCount(count: number) {
this._tableCount.set(count);
}
Expand Down
42 changes: 28 additions & 14 deletions mathesar_ui/src/models/Table.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { api } from '@mathesar/api/rpc';
import type {
RawTableWithMetadata,
TablePrivilege,
} from '@mathesar/api/rpc/tables';
import type { RawTableWithMetadata } from '@mathesar/api/rpc/tables';
import AsyncRpcApiStore from '@mathesar/stores/AsyncRpcApiStore';
import { ImmutableMap } from '@mathesar-component-library';
import { CancellablePromise, ImmutableMap } from '@mathesar-component-library';

import { ObjectCurrentAccess } from './internal/ObjectCurrentAccess';
import type { Role } from './Role';
import type { Schema } from './Schema';

Expand All @@ -18,13 +16,9 @@ export class Table {

metadata;

schema;
readonly schema;

owner_oid: Role['oid'];

current_role_priv: TablePrivilege[];

current_role_owns: boolean;
readonly currentAccess;

constructor(props: {
schema: Schema;
Expand All @@ -34,12 +28,32 @@ export class Table {
this.name = props.rawTableWithMetadata.name;
this.description = props.rawTableWithMetadata.description;
this.metadata = props.rawTableWithMetadata.metadata;
this.owner_oid = props.rawTableWithMetadata.owner_oid;
this.current_role_priv = props.rawTableWithMetadata.current_role_priv;
this.current_role_owns = props.rawTableWithMetadata.current_role_owns;
this.currentAccess = new ObjectCurrentAccess(props.rawTableWithMetadata);
this.schema = props.schema;
}

updateOwner(newOwner: Role['oid']) {
const promise = api.tables.privileges
.transfer_ownership({
database_id: this.schema.database.id,
table_oid: this.oid,
new_owner_oid: newOwner,
})
.run();

return new CancellablePromise(
(resolve, reject) => {
promise
.then((result) => {
this.currentAccess.set(result);
return resolve(this);
}, reject)
.catch(reject);
},
() => promise.cancel(),
);
}

constructTablePrivilegesStore() {
return new AsyncRpcApiStore(api.tables.privileges.list_direct, {
postProcess: (rawTablePrivilegesForRoles) =>
Expand Down
45 changes: 45 additions & 0 deletions mathesar_ui/src/models/UnderlyingDatabase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { api } from '@mathesar/api/rpc';
import type { RawUnderlyingDatabase } from '@mathesar/api/rpc/databases';
import { CancellablePromise } from '@mathesar-component-library';

import type { Database } from './Database';
import { ObjectCurrentAccess } from './internal/ObjectCurrentAccess';
import type { Role } from './Role';

export class UnderlyingDatabase {
readonly oid: number;

readonly currentAccess;

readonly database: Database;

constructor(props: {
database: Database;
rawUnderlyingDatabase: RawUnderlyingDatabase;
}) {
this.oid = props.rawUnderlyingDatabase.oid;
this.currentAccess = new ObjectCurrentAccess(props.rawUnderlyingDatabase);
this.database = props.database;
}

updateOwner(newOwner: Role['oid']) {
const promise = api.databases.privileges
.transfer_ownership({
database_id: this.database.id,
new_owner_oid: newOwner,
})
.run();

return new CancellablePromise(
(resolve, reject) => {
promise
.then((result) => {
this.currentAccess.set(result);
return resolve(this);
}, reject)
.catch(reject);
},
() => promise.cancel(),
);
}
}
Loading

0 comments on commit 8d0d01b

Please sign in to comment.