Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement basic Table data model on the frontend and Table Permissions modal -> 'Share' tab #3838

Merged
merged 13 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions mathesar_ui/src/api/rpc/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,34 @@ import type { RecursivePartial } from '@mathesar/component-library';
import { rpcMethodTypeContainer } from '@mathesar/packages/json-rpc-client-builder';

import type { ColumnTypeOptions } from './columns';
import type { RawDatabase } from './databases';
import type { RawRole } from './roles';

export const allTablePrivileges = [
'SELECT',
'INSERT',
'UPDATE',
'DELETE',
'TRUNCATE',
'REFERENCES',
'TRIGGER',
] as const;
export type TablePrivilege = (typeof allTablePrivileges)[number];

export interface RawTable {
oid: number;
name: string;
/** The OID of the schema containing the table */
schema: number;
description: string | null;
owner_oid: RawRole['oid'];
current_role_priv: TablePrivilege[];
current_role_owns: boolean;
}

export interface RawTablePrivilegesForRole {
role_oid: RawRole['oid'];
direct: TablePrivilege[];
}

interface TableMetadata {
Expand All @@ -28,15 +49,15 @@ interface TableMetadata {
record_summary_template: string | null;
}

export interface Table extends RawTable {
export interface RawTableWithMetadata extends RawTable {
metadata: TableMetadata | null;
}

/** [table oid, column attnum][] */
export type JoinPath = [number, number][][];

export interface JoinableTable {
target: Table['oid'];
target: RawTableWithMetadata['oid'];
join_path: JoinPath;
/**
* [Constraint OID, is_reversed]
Expand All @@ -62,7 +83,7 @@ export interface JoinableTablesResult {
target_table_info: Record<
string,
{
name: Table['name'];
name: RawTableWithMetadata['name'];
/** Keys are stringified column attnum values */
columns: Record<
string,
Expand Down Expand Up @@ -100,7 +121,7 @@ export const tables = {
database_id: number;
schema_oid: number;
},
Table[]
RawTableWithMetadata[]
>(),

get: rpcMethodTypeContainer<
Expand All @@ -116,7 +137,7 @@ export const tables = {
database_id: number;
table_oid: number;
},
Table
RawTableWithMetadata
>(),

/** Returns the oid of the table created */
Expand Down Expand Up @@ -205,4 +226,23 @@ export const tables = {
void
>(),
},

privileges: {
list_direct: rpcMethodTypeContainer<
{
database_id: RawDatabase['id'];
table_oid: RawTable['oid'];
},
Array<RawTablePrivilegesForRole>
>(),

replace_for_roles: rpcMethodTypeContainer<
{
database_id: RawDatabase['id'];
table_oid: RawTable['oid'];
privileges: Array<RawTablePrivilegesForRole>;
},
Array<RawTablePrivilegesForRole>
>(),
},
};
2 changes: 1 addition & 1 deletion mathesar_ui/src/components/SelectTable.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { _ } from 'svelte-i18n';

import type { Table } from '@mathesar/api/rpc/tables';
import type { Table } from '@mathesar/models/Table';
import { Select } from '@mathesar-component-library';
import type { SelectProps } from '@mathesar-component-library/types';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import type { Table } from '@mathesar/api/rpc/tables';
import type { Table } from '@mathesar/models/Table';
import { importVerifiedTables } from '@mathesar/stores/tables';
import type { SelectProps } from '@mathesar-component-library/types';

Expand Down
2 changes: 1 addition & 1 deletion mathesar_ui/src/components/TableName.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script lang="ts">
import type { ComponentProps } from 'svelte';

import type { Table } from '@mathesar/api/rpc/tables';
import { iconTable } from '@mathesar/icons';
import type { Table } from '@mathesar/models/Table';
import { tableRequiresImportConfirmation } from '@mathesar/utils/tables';

import NameWithIcon from './NameWithIcon.svelte';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import type { Table } from '@mathesar/api/rpc/tables';
import { iconExpandRight } from '@mathesar/icons';
import type { Table } from '@mathesar/models/Table';
import { getRecordSelectorFromContext } from '@mathesar/systems/record-selector/RecordSelectorController';
import { Button, Icon, iconSearch } from '@mathesar-component-library';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import { meta } from 'tinro';

import type { QueryInstance } from '@mathesar/api/rest/types/queries';
import type { Table } from '@mathesar/api/rpc/tables';
import { iconTable } from '@mathesar/icons';
import type { Database } from '@mathesar/models/Database';
import type { Schema } from '@mathesar/models/Schema';
import type { Table } from '@mathesar/models/Table';
import { getExplorationPageUrl } from '@mathesar/routes/urls';
import { queries as queriesStore } from '@mathesar/stores/queries';
import { currentTableId, currentTables } from '@mathesar/stores/tables';
Expand Down
2 changes: 1 addition & 1 deletion mathesar_ui/src/components/breadcrumb/breadcrumbTypes.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { QueryInstance } from '@mathesar/api/rest/types/queries';
import type { Table } from '@mathesar/api/rpc/tables';
import type {
ComponentAndProps,
IconProps,
} from '@mathesar/component-library/types';
import type { Database } from '@mathesar/models/Database';
import type { Schema } from '@mathesar/models/Schema';
import type { Table } from '@mathesar/models/Table';

export interface BreadcrumbItemHome {
type: 'home';
Expand Down
2 changes: 1 addition & 1 deletion mathesar_ui/src/components/cell-fabric/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Column } from '@mathesar/api/rpc/columns';
import type { Table } from '@mathesar/api/rpc/tables';
import type { Table } from '@mathesar/models/Table';
import type { CellInfo } from '@mathesar/stores/abstract-types/types';
import type { RecordSummariesForSheet } from '@mathesar/stores/table-data/record-summaries/recordSummaryUtils';
import type { ComponentAndProps } from '@mathesar-component-library/types';
Expand Down
11 changes: 11 additions & 0 deletions mathesar_ui/src/i18n/languages/en/dict.json
Original file line number Diff line number Diff line change
Expand Up @@ -566,14 +566,24 @@
"sync_external_changes_data_help": "External changes to data (e.g. adding or editing rows) will be automatically reflected without clicking this button.",
"sync_external_changes_structure_help": "If you make structural changes to the database outside Mathesar (e.g. using another tool to add a schema, table, or column), those changes will not be reflected in Mathesar until you manually sync them with this button.",
"table": "Table",
"table_access_read_help": "Can read table records",
"table_access_write_help": "Can read, update, delete, and create table records",
"table_delete_permanent_warning": "Warning: This action is permanent and once deleted, the table cannot be recovered.",
"table_does_not_link": "This table does not link to any other tables",
"table_name": "Table Name",
"table_name_already_exists": "A table with that name already exists.",
"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_permissions": "Table Permissions",
"table_preview": "Table Preview",
"table_privilege_delete_help": "Allow deletion of records within the table.",
"table_privilege_insert_help": "Allow creation of new records within the table.",
"table_privilege_references_help": "Allow creation of foreign key references to the table.",
"table_privilege_select_help": "Allow reading data from the table.",
"table_privilege_trigger_help": "Allow creation of triggers on the table.",
"table_privilege_truncate_help": "Allow truncation (removal of all records) of the table.",
"table_privilege_update_help": "Allow updating of records within the table.",
"table_with_name_already_exists": "A table with that name already exists.",
"tables": "Tables",
"tables_matching_search": "{count, plural, one {{count} table matches [searchValue]} other {{count} tables match [searchValue]}}",
Expand Down Expand Up @@ -660,6 +670,7 @@
"while_upgrading": "While Upgrading",
"why_is_this_needed": "Why is this needed?",
"window_remains_open_mathesar_unusable": "This window will remain open but all features within Mathesar will be unusable.",
"write": "Write",
"yes": "Yes",
"yes_summarize_as_list": "Yes, summarize as a list",
"yesterday": "Yesterday"
Expand Down
5 changes: 3 additions & 2 deletions mathesar_ui/src/models/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ export class Schema {

readonly current_role_owns: boolean;

readonly isPublicSchema = derived(this.name, ($name) => $name === 'public');
readonly isPublicSchema;

readonly database: Database;

constructor(props: { database: Database; rawSchema: RawSchema }) {
this.oid = props.rawSchema.oid;
this._name = writable(props.rawSchema.name);
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;
Expand Down Expand Up @@ -75,7 +76,7 @@ export class Schema {
);
}

updateTableCount(count: number) {
setTableCount(count: number) {
this._tableCount.set(count);
}

Expand Down
54 changes: 54 additions & 0 deletions mathesar_ui/src/models/Table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { api } from '@mathesar/api/rpc';
import type {
RawTableWithMetadata,
TablePrivilege,
} from '@mathesar/api/rpc/tables';
import AsyncRpcApiStore from '@mathesar/stores/AsyncRpcApiStore';
import { ImmutableMap } from '@mathesar-component-library';

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

export class Table {
oid: number;

name: string;

description: string | null;

metadata;

schema;

owner_oid: Role['oid'];

current_role_priv: TablePrivilege[];

current_role_owns: boolean;

constructor(props: {
schema: Schema;
rawTableWithMetadata: RawTableWithMetadata;
}) {
this.oid = props.rawTableWithMetadata.oid;
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.schema = props.schema;
}

constructTablePrivilegesStore() {
return new AsyncRpcApiStore(api.tables.privileges.list_direct, {
postProcess: (rawTablePrivilegesForRoles) =>
new ImmutableMap(
rawTablePrivilegesForRoles.map((rawTablePrivilegesForRole) => [
rawTablePrivilegesForRole.role_oid,
rawTablePrivilegesForRole,
]),
),
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
onProceed: async () => {
await deleteSchemaAPI(schema);
// TODO: Create common util to handle data clearing & sync between stores
removeTablesStore(database, schema);
removeTablesStore(schema);
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<div>
{#if user}
<div>{userName}</div>
<div>{user.email}</div>
<div>{user.email ?? ''}</div>
{:else}
{collaborator.userId}
{/if}
Expand Down
5 changes: 2 additions & 3 deletions mathesar_ui/src/pages/exploration/Header.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
import { getExplorationEditorPageUrl } from '@mathesar/routes/urls';
import { Button, Icon } from '@mathesar-component-library';

import ShareExplorationDropdown from './ShareExplorationDropdown.svelte';

export let database: Database;
export let schema: Schema;
export let query: QueryInstance;
Expand All @@ -33,7 +31,8 @@
>
<span>{$_('edit_in_data_explorer')}</span>
</a>
<ShareExplorationDropdown id={query.id} />
<!-- TODO: Display Share option when we re-implement it with the new permissions structure -->
<!-- <ShareExplorationDropdown id={query.id} /> -->
{/if}
<Button
appearance="secondary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import type { DataFile } from '@mathesar/api/rest/types/dataFiles';
import { api } from '@mathesar/api/rpc';
import type { Column } from '@mathesar/api/rpc/columns';
import type { ColumnPreviewSpec, Table } from '@mathesar/api/rpc/tables';
import type { ColumnPreviewSpec } from '@mathesar/api/rpc/tables';
import {
Field,
FieldLayout,
Expand All @@ -15,8 +15,8 @@
} from '@mathesar/components/form';
import InfoBox from '@mathesar/components/message-boxes/InfoBox.svelte';
import { iconDeleteMajor } from '@mathesar/icons';
import type { Database } from '@mathesar/models/Database';
import type { Schema } from '@mathesar/models/Schema';
import type { Table } from '@mathesar/models/Table';
import { runner } from '@mathesar/packages/json-rpc-client-builder';
import {
getImportPreviewPageUrl,
Expand Down Expand Up @@ -171,7 +171,7 @@
async function finishImport() {
try {
await updateTable({
database: schema.database,
schema,
table: {
oid: table.oid,
name: $customizedTableName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
}

$: void (async () => {
const table = (await tableFetch.run({ database, tableOid: tableId }))
const table = (await tableFetch.run({ schema, tableOid: tableId }))
.resolvedValue;
if (!table) {
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { dataFilesApi } from '@mathesar/api/rest/dataFiles';
import type { DataFile } from '@mathesar/api/rest/types/dataFiles';
import type { Column } from '@mathesar/api/rpc/columns';
import type { Table } from '@mathesar/api/rpc/tables';
import { getCellCap } from '@mathesar/components/cell-fabric/utils';
import type { Database } from '@mathesar/models/Database';

Check warning on line 5 in mathesar_ui/src/pages/import/preview/importPreviewPageUtils.ts

View workflow job for this annotation

GitHub Actions / Run front end linter

'Database' is defined but never used
import type { Schema } from '@mathesar/models/Schema';
import type { Table } from '@mathesar/models/Table';
import { getAbstractTypeForDbType } from '@mathesar/stores/abstract-types';
import type {
AbstractType,
Expand Down
5 changes: 2 additions & 3 deletions mathesar_ui/src/pages/record/RecordPage.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<script lang="ts">
import type { Table } from '@mathesar/api/rpc/tables';
import LayoutWithHeader from '@mathesar/layouts/LayoutWithHeader.svelte';
import type { Table } from '@mathesar/models/Table';
import { makeSimplePageTitle } from '@mathesar/pages/pageTitleUtils';
import { abstractTypesMap } from '@mathesar/stores/abstract-types';
import { currentDatabase } from '@mathesar/stores/databases';
import { TableStructure } from '@mathesar/stores/table-data';
import { currentTable } from '@mathesar/stores/tables';

Expand All @@ -15,7 +14,7 @@

$: table = $currentTable as Table;
$: tableStructure = new TableStructure({
database: $currentDatabase,
database: table.schema.database,
table,
abstractTypesMap,
});
Expand Down
Loading
Loading