diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte index 93034a2d5..cfefc3a7f 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte @@ -400,6 +400,8 @@ $: if (!$showCreateColumnSheet.show) { createMoreColumns = false; } + + $: currentRowId = $databaseRowSheetOptions.row?.$id ?? $databaseRowSheetOptions.rowId; @@ -456,7 +458,6 @@ - + {#key currentRowId} + + {/key} { if (row) { work = initWork(); - focusFirstInput(); + requestAnimationFrame(() => focusFirstInput()); } else { work = null; } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/sheetOptions.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/sheetOptions.svelte index 761178f79..3fdf50d14 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/sheetOptions.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/sheetOptions.svelte @@ -117,15 +117,20 @@ if (type === 'header') { if (isSequence) { - return ['sort-asc', 'sort-desc'].includes(item.action ?? ''); + return ['sort-asc', 'sort-desc'].includes(item?.action); } - if (['delete', 'update', 'duplicate-header'].includes(item.action) && isSystemColumn) { + if (['delete', 'update', 'duplicate-header'].includes(item?.action) && isSystemColumn) { + return false; + } + + // hide column-left and create-index for $id (first column, already indexed) + if (columnId === '$id' && ['column-left', 'create-index'].includes(item?.action)) { return false; } // hide sort options for relationship columns - if (isRelationship(column) && ['sort-asc', 'sort-desc'].includes(item.action ?? '')) { + if (isRelationship(column) && ['sort-asc', 'sort-desc'].includes(item?.action)) { return false; } } 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 324a1e087..ecf308d49 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 @@ -53,6 +53,8 @@ Button, Layout, Link, + Popover, + Keyboard, Badge, FloatingActionBar, Icon, @@ -78,7 +80,8 @@ IconSwitchHorizontal, IconText, IconToggle, - IconViewList + IconViewList, + IconArrowExpand } from '@appwrite.io/pink-icons-svelte'; import type { HeaderCellAction, RowCellAction } from './sheetOptions.svelte'; import SheetOptions from './sheetOptions.svelte'; @@ -120,7 +123,9 @@ : 24; let selectedRows = []; + let showExpandIconForId: number | null = null; let spreadsheetContainer: SpreadsheetContainer; + let previouslyFocusedElement: Element | null = null; let currentPage = 1; let jumpToPageReactive = 0; @@ -170,8 +175,8 @@ { id: '$id', title: '$id', - width: getColumnWidth('$id', 225), - minimumWidth: 225, + width: getColumnWidth('$id', 250), + minimumWidth: 250, draggable: false, type: 'string', icon: IconFingerPrint, @@ -537,9 +542,14 @@ } } else if (type === 'row') { if (action === 'update') { - $databaseRowSheetOptions.show = true; - $databaseRowSheetOptions.row = row; - $databaseRowSheetOptions.title = 'Update row'; + databaseRowSheetOptions.update((opts) => { + return { + ...opts, + row, + show: true, + title: 'Update row' + }; + }); } if (action === 'duplicate-row') { @@ -747,6 +757,13 @@ $: totalPages = Math.ceil($rows.total / SPREADSHEET_PAGE_LIMIT) || 1; $: rowSelection = !$spreadsheetLoading && !$paginatedRowsLoading ? true : ('disabled' as const); + + $: if (!$databaseRowSheetOptions.show && previouslyFocusedElement) { + requestAnimationFrame(() => { + (previouslyFocusedElement as HTMLElement)?.focus(); + previouslyFocusedElement = null; + }); + } @@ -776,6 +793,14 @@ bottomActionTooltip={{ text: 'Create row', placement: 'top-end' + }} + expandKbdShortcut="Cmd+Enter" + on:expandKbdShortcut={({ detail }) => { + const focusedRowId = detail.rowId; + const focusedRow = $rows.rows.find((row) => row.$id === focusedRowId); + + previouslyFocusedElement = document.activeElement; + onSelectSheetOption('update', null, 'row', focusedRow); }}> {#each $tableColumns as column (column.id)} @@ -867,56 +892,133 @@ valueWithoutHover={row.$sequence}> {#each $tableColumns as { id: columnId, isEditable } (columnId)} {@const rowColumn = $columns.find((col) => col.key === columnId)} - - {#if columnId === '$id'} - {row.$id} - {:else if columnId === '$createdAt' || columnId === '$updatedAt'} - - {:else if columnId === 'actions'} - - onSelectSheetOption(option, null, 'row', row)} - onVisibilityChanged={(visible) => { - canShowDatetimePopover = !visible; - }}> - {#snippet children(toggle)} - - - - {/snippet} - - {:else if isRelationship(rowColumn)} - {@const args = getDisplayNamesForTable(row[columnId])} - {#if !isRelationshipToMany(rowColumn)} - {#if row[columnId]} - {@const displayValue = args - .map((arg) => row[columnId]?.[arg]) - .filter(Boolean) - .join(' | ')} + {#if columnId === '$id'} + + + + + Expand row + + + + + + + + + + + + {:else} + + {#if columnId === '$createdAt' || columnId === '$updatedAt'} + + {:else if columnId === 'actions'} + + onSelectSheetOption(option, null, 'row', row)} + onVisibilityChanged={(visible) => { + canShowDatetimePopover = !visible; + }}> + {#snippet children(toggle)} + + + + {/snippet} + + {:else if isRelationship(rowColumn)} + {@const args = getDisplayNamesForTable(row[columnId])} + {#if !isRelationshipToMany(rowColumn)} + {#if row[columnId]} + {@const displayValue = args + .map((arg) => row[columnId]?.[arg]) + .filter(Boolean) + .join(' | ')} + + {#if displayValue} + { + $databaseRelatedRowSheetOptions.tableId = + row[columnId]?.['$tableId']; + $databaseRelatedRowSheetOptions.rows = + row[columnId]?.['$id']; + $databaseRelatedRowSheetOptions.show = true; + }}> + {displayValue} + + {:else} + + {/if} {:else} {/if} {:else} - + {@const itemsNum = row[columnId]?.length} + Items {/if} + {:else if isSpatialType(rowColumn) && row[columnId] !== null} + + {JSON.stringify(row[columnId])} + {:else} - {@const itemsNum = row[columnId]?.length} - Items - {/if} - {:else if isSpatialType(rowColumn) && row[columnId] !== null} - - {JSON.stringify(row[columnId])} - - {:else} - {@const value = row[columnId]} - {@const formatted = formatColumn(row[columnId])} - {@const isEmptyArray = formatted === 'Empty'} - {@const isDatetimeAttribute = rowColumn.type === 'datetime'} - {@const isEncryptedAttribute = - isString(rowColumn) && rowColumn.encrypt} - {#if isDatetimeAttribute} - - Timestamp - {toLocaleDateTime(value, true)} - - {:else if isEncryptedAttribute} - - {:else if formatted.length > 20} - + {@const value = row[columnId]} + {@const formatted = formatColumn(row[columnId])} + {@const isEmptyArray = formatted === 'Empty'} + {@const isDatetimeAttribute = rowColumn.type === 'datetime'} + {@const isEncryptedAttribute = + isString(rowColumn) && rowColumn.encrypt} + {#if isDatetimeAttribute} + + Timestamp + {toLocaleDateTime(value, true)} + + {:else if isEncryptedAttribute} + + {:else if formatted.length > 20} + + + {formatted} + + + {formatted} + + + {:else if formatted === 'null'} + + {:else if isEmptyArray} + + {:else} {formatted} - - {formatted} - - - {:else if formatted === 'null'} - - {:else if isEmptyArray} - - {:else} - - {formatted} - + {/if} {/if} - {/if} - - {@const isRelatedToMany = isRelationshipToMany(rowColumn)} - {@const hasItems = isRelatedToMany - ? row[columnId]?.length - : false} + + {@const isRelatedToMany = isRelationshipToMany(rowColumn)} + {@const hasItems = isRelatedToMany + ? row[columnId]?.length + : false} - paginatedRows.update(index, row)} - onRevert={(row) => paginatedRows.update(index, row)} - openSideSheet={() => { - close(); /* closes the editor */ + paginatedRows.update(index, row)} + onRevert={(row) => paginatedRows.update(index, row)} + openSideSheet={() => { + close(); /* closes the editor */ - if (isRelationshipToMany(rowColumn)) { - openSideSheetForRelationsToMany( - row[columnId], - rowColumn - ); - } else { - onSelectSheetOption('update', null, 'row', row); - } - }} /> - - + if (isRelationshipToMany(rowColumn)) { + openSideSheetForRelationsToMany( + row[columnId], + rowColumn + ); + } else { + onSelectSheetOption('update', null, 'row', row); + } + }} /> + + + {/if} {/each} {/if}