diff --git a/src/lib/components/sidebar.svelte b/src/lib/components/sidebar.svelte
index 112dadff9..172bc7d01 100644
--- a/src/lib/components/sidebar.svelte
+++ b/src/lib/components/sidebar.svelte
@@ -258,8 +258,7 @@
>SettingsSettings
Settings
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte
index f3ab9b7b8..8ac91b246 100644
--- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte
+++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte
@@ -27,7 +27,8 @@
randomDataModalState,
spreadsheetLoading,
showCreateIndexSheet,
- type SortState
+ type SortState,
+ Deletion
} from './store';
import RelationshipsModal from './relationshipsModal.svelte';
import type { Column, ColumnType } from '$lib/helpers/types';
@@ -67,6 +68,7 @@
import type { HeaderCellAction, RowCellAction } from './sheetOptions.svelte';
import { copy } from '$lib/helpers/copy';
import { debounce } from '$lib/helpers/debounce';
+ import { writable } from 'svelte/store';
export let data: PageData;
export let showRecordsCreateSheet: {
@@ -74,107 +76,41 @@
row: Models.Row | null;
};
- const databaseId = page.params.database;
+ $: rows = writable(data.rows);
const tableId = page.params.table;
+ const databaseId = page.params.database;
+ const minimumWidth = 168;
+ const emptyCellsLimit = $isSmallViewport ? 12 : 18;
+ const selected = preferences.getCustomTableColumns(page.params.table);
+ const SYSTEM_KEYS = new Set([
+ '$tableId',
+ '$databaseId'
+ ]); /* TODO: should be fixed at the sdk level! */
+
+ let selectedRows = [];
let displayNames = {};
let showRelationships = false;
let relationshipData: Partial[];
let selectedRelationship: Models.ColumnRelationship = null;
- $: rows = data.rows;
+ let showDelete = false;
+ let showColumnDelete = false;
+ let deleteConfirmationChecked = false;
+ let selectedRowForDelete: Models.Row['$id'] | null = null;
onMount(async () => {
displayNames = preferences.getDisplayNames();
columnsOrder.set(preferences.getColumnOrder(tableId));
columnsWidth.set(preferences.getColumnWidths(tableId));
+ makeTableColumns();
sortState.set(data.currentSort as SortState);
});
onDestroy(() => ($showCreateAttributeSheet.show = false));
- function saveColumnsOrder(newOrder: string[], update: boolean = true) {
- if (update) {
- columnsOrder.set(newOrder);
- }
-
- preferences.saveColumnOrder(
- data.organization.$id ?? data.project.teamId,
- tableId,
- newOrder
- );
- }
-
- function formatArray(array: unknown[]) {
- if (array.length === 0) return '[ ]';
-
- let formattedFields: string[] = [];
- for (const item of array) {
- if (typeof item === 'string') {
- formattedFields.push(`"${item}"`);
- } else {
- formattedFields.push(`${item}`);
- }
- }
-
- return `[${formattedFields.join(', ')}]`;
- }
-
- function formatColumn(column: unknown) {
- let formattedColumn: string;
-
- if (typeof column === 'string') {
- formattedColumn = column;
- } else if (Array.isArray(column)) {
- formattedColumn = formatArray(column);
- } else if (column === null) {
- formattedColumn = 'null';
- } else {
- formattedColumn = `${column}`;
- }
-
- return formattedColumn;
- }
-
- function getAppropriateIcon(type: string): ComponentType {
- switch (type) {
- case 'string':
- return IconText;
- case 'float':
- case 'integer':
- return IconHashtag;
- case 'boolean':
- return IconToggle;
- case 'datetime':
- return IconCalendar;
- case 'email':
- return IconMail;
- case 'ip':
- return IconLocationMarker;
- case 'url':
- return IconLink;
- case 'enum':
- return IconViewList;
- case 'relationship':
- return IconRelationship;
- }
- }
-
- function getColumnWidth(
- columnId: string,
- defaultWidth: number | { min: number }
- ): number | { min: number; max?: number } {
- const savedWidth = $columnsWidth[columnId];
- if (!savedWidth) return defaultWidth;
-
- return savedWidth.resized;
- }
-
- $: selected = preferences.getCustomTableColumns(page.params.table);
-
- const minimumWidth = 168;
- $: if ($table.columns && $columnsOrder && $columnsWidth) {
+ function makeTableColumns() {
const baseColumns = $table.columns.map((col) => ({
id: col.key,
title: col.key,
@@ -260,11 +196,97 @@
);
}
- $: selectedRows = [];
- let showColumnDelete = false;
+ function getColumnWidth(
+ columnId: string,
+ defaultWidth: number | { min: number }
+ ): number | { min: number; max?: number } {
+ const savedWidth = $columnsWidth?.[columnId];
+ if (!savedWidth) return defaultWidth;
- let showDelete = false;
- let selectedRowForDelete: Models.Row['$id'] | null = null;
+ return savedWidth.resized;
+ }
+
+ function saveColumnsOrder(newOrder: string[], update: boolean = true) {
+ if (update) {
+ columnsOrder.set(newOrder);
+ }
+
+ preferences.saveColumnOrder(
+ data.organization.$id ?? data.project.teamId,
+ tableId,
+ newOrder
+ );
+ }
+
+ function saveColumnsWidth(column: { columnId: string; newWidth: number }) {
+ const fixedWidth =
+ $tableColumns.find((col) => col.id === column.columnId)?.width ?? column.newWidth;
+
+ columnsWidth.update((widths) => ({
+ ...widths,
+ [column.columnId]: {
+ fixed: fixedWidth,
+ resized: Math.ceil(column.newWidth)
+ }
+ }));
+
+ saveColumnWidthsToPreferences(column);
+ }
+
+ function formatArray(array: unknown[]) {
+ if (array.length === 0) return '[ ]';
+
+ let formattedFields: string[] = [];
+ for (const item of array) {
+ if (typeof item === 'string') {
+ formattedFields.push(`"${item}"`);
+ } else {
+ formattedFields.push(`${item}`);
+ }
+ }
+
+ return `[${formattedFields.join(', ')}]`;
+ }
+
+ function formatColumn(column: unknown) {
+ let formattedColumn: string;
+
+ if (typeof column === 'string') {
+ formattedColumn = column;
+ } else if (Array.isArray(column)) {
+ formattedColumn = formatArray(column);
+ } else if (column === null) {
+ formattedColumn = 'null';
+ } else {
+ formattedColumn = `${column}`;
+ }
+
+ return formattedColumn;
+ }
+
+ function getAppropriateIcon(type: string): ComponentType {
+ switch (type) {
+ case 'string':
+ return IconText;
+ case 'float':
+ case 'integer':
+ return IconHashtag;
+ case 'boolean':
+ return IconToggle;
+ case 'datetime':
+ return IconCalendar;
+ case 'email':
+ return IconMail;
+ case 'ip':
+ return IconLocationMarker;
+ case 'url':
+ return IconLink;
+ case 'enum':
+ return IconViewList;
+ case 'relationship':
+ return IconRelationship;
+ }
+ }
async function sort(query: string | null) {
$spreadsheetLoading = true;
@@ -355,27 +377,6 @@
}
}
- enum Deletion {
- 'setNull' = 'Set rpw ID as NULL in all related rows',
- 'cascade' = 'All related rows will be deleted',
- 'restrict' = 'Row can not be deleted'
- }
-
- $: relatedColumns = $columns?.filter(
- (attribute) =>
- isRelationship(attribute) &&
- // One-to-One are always included
- (attribute.relationType === 'oneToOne' ||
- // One-to-Many: Only if parent is deleted
- (attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
- // Many-to-One: Only include if child is deleted
- (attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
- // Many-to-Many: Only include if the parent is being deleted
- (isRelationshipToMany(attribute) && attribute.side === 'parent'))
- ) as Models.ColumnRelationship[];
-
- let checked = false;
-
async function onSelectSheetOption(
action: HeaderCellAction | RowCellAction,
columnId: string,
@@ -457,39 +458,8 @@
}
}
- const saveColumnsWidth = debounce((column: { columnId: string; newWidth: number }) => {
- const fixedWidth =
- $tableColumns.find((col) => col.id === column.columnId)?.width ?? column.newWidth;
-
- console.log(
- JSON.stringify(
- {
- [column.columnId]: {
- fixed: fixedWidth,
- resized: Math.ceil(column.newWidth)
- }
- },
- null,
- 2
- )
- );
-
- preferences.saveColumnWidths(data.organization.$id ?? data.project.teamId, tableId, {
- [column.columnId]: {
- fixed: fixedWidth,
- resized: Math.ceil(column.newWidth)
- }
- });
- }, 1000);
-
- // TODO: should be fixed at the sdk level!
- const SYSTEM_KEYS = new Set(['$tableId', '$databaseId']);
-
- async function updateRow(row: Models.Row, index: number) {
- rows.rows[index] = row as Models.DefaultRow;
-
+ async function updateRowContents(row: Models.Row) {
try {
- // TODO: should be fixed at the sdk level!
const onlyData = Object.fromEntries(
Object.entries(row).filter(([key]) => !SYSTEM_KEYS.has(key))
);
@@ -513,25 +483,53 @@
}
}
- const emptyCellsLimit = $isSmallViewport ? 12 : 18;
+ const saveColumnWidthsToPreferences = debounce(
+ (column: { columnId: string; newWidth: number }) => {
+ const fixedWidth =
+ $tableColumns.find((col) => col.id === column.columnId)?.width ?? column.newWidth;
+
+ preferences.saveColumnWidths(data.organization.$id ?? data.project.teamId, tableId, {
+ [column.columnId]: {
+ fixed: fixedWidth,
+ resized: Math.ceil(column.newWidth)
+ }
+ });
+ },
+ 1000
+ );
+
+ $: relatedColumns = $columns?.filter(
+ (attribute) =>
+ isRelationship(attribute) &&
+ // One-to-One are always included
+ (attribute.relationType === 'oneToOne' ||
+ // One-to-Many: Only if parent is deleted
+ (attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
+ // Many-to-One: Only include if child is deleted
+ (attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
+ // Many-to-Many: Only include if the parent is being deleted
+ (isRelationshipToMany(attribute) && attribute.side === 'parent'))
+ ) as Models.ColumnRelationship[];
$: emptyCellsCount =
- data.rows.rows.length >= emptyCellsLimit ? 0 : emptyCellsLimit - data.rows.rows.length;
-
- $: reInitSpreadsheetKey = `${$table.columns.length}#${$columnsOrder.length}`;
+ $rows.rows.length >= emptyCellsLimit ? 0 : emptyCellsLimit - $rows.rows.length;
$: canShowDatetimePopover = true;
+
+ $: if ($table.columns) {
+ makeTableColumns();
+ }
- {#key reInitSpreadsheetKey}
+ {#key $rows.rows.length}
- {@const row = rows.rows[item.index]}
+ {@const row = $rows.rows[item.index]}
{#each $tableColumns as { id: columnId, isEditable } (columnId)}
- {@const formatted = formatColumn(row[columnId])}
{@const rowColumn = $columns.find((col) => col.key === columnId)}
+ value={$rows.rows[item.index][columnId]}>
{#if columnId === '$sequence'}
{row.$sequence}
@@ -720,11 +715,9 @@
{
- updateRow(newRow, index);
- }} />
+ bind:row={$rows.rows[item.index]}
+ onRowStructureUpdate={updateRowContents} />
{/each}
@@ -740,7 +733,7 @@
{selectedRows.length
? `${selectedRows.length} rows selected`
- : `${rows.total} rows`}
+ : `${$rows.total} rows`}
@@ -832,7 +825,11 @@
To change the selection edit the relationship settings.
-
+
Delete {isSingle ? 'document' : 'documents'} from
{$table.name}
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts
index 6240c040a..dd2c015de 100644
--- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts
+++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts
@@ -135,3 +135,9 @@ export const randomDataModalState = writable({
});
export const spreadsheetLoading = writable(false);
+
+export enum Deletion {
+ 'setNull' = 'Set rpw ID as NULL in all related rows',
+ 'cascade' = 'All related rows will be deleted',
+ 'restrict' = 'Row can not be deleted'
+}