From 498ba4d8c6f08830da3bf78870b86fa4a50a5964 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 2 Oct 2025 10:41:31 +0530 Subject: [PATCH 01/47] update: make empty sheet interactive [wip]. --- .../table-[table]/layout/emptySheet.svelte | 216 ++++++++++++------ 1 file changed, 149 insertions(+), 67 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte index bdc92fb75f..b5a1027b9d 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte @@ -94,53 +94,110 @@ const getCustomColumns = (): Column[] => customColumns.map((col: Column) => ({ ...col, - width: 180, hide: false, icon: columnOptions.find((colOpt) => colOpt.type === col?.type)?.icon, ...baseColProps })); - const getRowColumns = (): Column[] => [ - { - id: '$id', - title: '$id', - type: 'string', - width: 180, - icon: IconFingerPrint, - ...baseColProps - }, - ...getCustomColumns(), - { - id: '$createdAt', - title: '$createdAt', - type: 'datetime', - width: 180, - icon: IconCalendar, - ...baseColProps - }, - { - id: '$updatedAt', - title: '$updatedAt', - type: 'datetime', - width: 180, - icon: IconCalendar, - ...baseColProps - }, - { - id: 'actions', - title: '', - type: 'string', - icon: IconPlus, - width: customColumns.length ? 555 : 832, - ...baseColProps - }, - { - id: 'empty', - title: '', - type: 'string', - ...baseColProps + const getRowColumns = (): Column[] => { + const minColumnWidth = 180; + const fixedWidths = { id: 180, actions: 40 }; + const hasCustomColumns = customColumns.length > 0; + + const customColumnsData = getCustomColumns(); + + // Calculate column widths based on whether we have custom columns + let columnWidths = { + id: fixedWidths.id, + createdAt: fixedWidths.id, + updatedAt: fixedWidths.id, + custom: minColumnWidth, + actions: hasCustomColumns ? fixedWidths.actions : 1387 + }; + + if (hasCustomColumns) { + const equalWidthColumns = [ + ...customColumnsData, + { id: '$createdAt' }, + { id: '$updatedAt' } + ]; + + const totalBaseWidth = + fixedWidths.id + fixedWidths.actions + equalWidthColumns.length * minColumnWidth; + + const viewportWidth = + spreadsheetContainer?.clientWidth || + (typeof window !== 'undefined' ? window.innerWidth : totalBaseWidth); + + const excessSpace = Math.max(0, viewportWidth - totalBaseWidth); + const extraPerColumn = + equalWidthColumns.length > 0 ? excessSpace / equalWidthColumns.length : 0; + const distributedWidth = minColumnWidth + extraPerColumn; + + columnWidths.createdAt = distributedWidth; + columnWidths.updatedAt = distributedWidth; + columnWidths.custom = distributedWidth; } - ]; + + const columns: Column[] = [ + { + id: '$id', + title: '$id', + type: 'string', + width: columnWidths.id, + icon: IconFingerPrint, + ...baseColProps + } + ]; + + if (hasCustomColumns) { + columns.push( + ...customColumnsData.map((col) => ({ + ...col, + width: columnWidths.custom + })) + ); + } + + columns.push( + { + id: '$createdAt', + title: '$createdAt', + type: 'datetime', + width: columnWidths.createdAt, + icon: IconCalendar, + ...baseColProps + }, + { + id: '$updatedAt', + title: '$updatedAt', + type: 'datetime', + width: columnWidths.updatedAt, + icon: IconCalendar, + ...baseColProps + }, + { + id: 'actions', + title: '', + type: 'string', + icon: IconPlus, + isAction: hasCustomColumns, + width: columnWidths.actions, + ...baseColProps + } + ); + + if (!hasCustomColumns) { + columns.push({ + id: 'empty', + title: '', + type: 'string', + ...baseColProps + }); + } + + return columns; + }; const getIndexesColumns = (): Column[] => [ @@ -165,6 +222,7 @@
0} data-mode={mode} bind:this={spreadsheetContainer}> @@ -179,20 +237,23 @@ }}> {#each spreadsheetColumns as column (column.id)} - {@const columnActionsById = column.id === 'actions'} - -
{ - if (columnActionsById && mode === 'rows') { - $showCreateColumnSheet.show = true; - $showCreateColumnSheet.title = 'Create column'; - $showCreateColumnSheet.columns = $tableColumns; - $showCreateColumnSheet.columnsOrder = $columnsOrder; - } - }}> + {#if column.isAction} + + { + if (mode === 'rows') { + $showCreateColumnSheet.show = true; + $showCreateColumnSheet.title = 'Create column'; + $showCreateColumnSheet.columns = $tableColumns; + $showCreateColumnSheet.columnsOrder = $columnsOrder; + } + }}> + + + + {:else} {/if} -
+ {/if} {/each}
@@ -236,6 +297,7 @@ {#if !$spreadsheetLoading}
0} data-collapsed-tabs={!$expandTabs} style:--dynamic-overlay-height={dynamicOverlayHeight}>
@@ -291,6 +353,31 @@ position: fixed; overflow: hidden; + & :global(.spreadsheet-container) { + overflow-x: auto; + overflow-y: auto; + } + + & :global([data-select='true']) { + opacity: 0.85; + pointer-events: none; + } + + &.custom-columns { + width: unset; + } + + &:not(.custom-columns) :global(.spreadsheet-container) { + overflow-x: hidden; + overflow-y: hidden; + } + + /* alternative selector for header selection */ + & :global(.sticky-header [data-select='true']) { + opacity: 1; + pointer-events: none; + } + &[data-mode='rows'] { & :global([role='rowheader'] :nth-last-child(2) [role='presentation']) { display: none; @@ -306,16 +393,6 @@ } } } - - & :global(.spreadsheet-container) { - overflow-x: hidden; - overflow-y: hidden; - } - - & :global([data-select='true']) { - opacity: 0.85; - pointer-events: none; - } } .spreadsheet-fade-bottom { @@ -342,6 +419,10 @@ @media (min-width: 1024px) { height: var(--dynamic-overlay-height, 70.35vh); } + + &.custom-columns { + pointer-events: none; + } } :global(.theme-dark) .spreadsheet-fade-bottom { @@ -358,6 +439,7 @@ left: 50%; bottom: 35%; position: fixed; + pointer-events: auto; @media (max-width: 768px) and (max-height: 768px) { left: unset; @@ -366,7 +448,7 @@ @media (max-width: 768px) and (max-height: 1024px) { left: unset; - bottom: 15% !important; + bottom: 20% !important; } @media (max-width: 1024px) and (max-height: 1024px) { From a53d5cc12a7858cef4e57f948b953db71c636907 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 2 Oct 2025 13:21:50 +0530 Subject: [PATCH 02/47] update: column selection for delete! --- .../(suggestions)/empty.svelte | 166 ++++++++++++++++-- .../(suggestions)/options.svelte | 6 +- 2 files changed, 156 insertions(+), 16 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index dc7b96e4be..b61a8b3038 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -38,6 +38,7 @@ import Options from './options.svelte'; import { InputSelect, InputText } from '$lib/elements/forms'; import { isCloud, VARS } from '$lib/system'; + import { fade } from 'svelte/transition'; import IconAINotification from './icon/aiNotification.svelte'; @@ -58,6 +59,8 @@ let scrollAnimationFrame: number | null = null; let creatingColumns = $state(false); + let selectedColumnId = $state(null); + let previousColumnId = $state(null); const baseColProps = { draggable: false, resizable: false }; const NOTIFICATION_AND_MOCK_DELAY = 1250; @@ -136,7 +139,8 @@ const hasRealColumns = customColumns.some((col) => !col.isPlaceholder); if (!hasRealColumns) { - // For placeholders or no columns, position overlay to cover custom columns area + // for placeholders or no columns, + // position overlay to cover custom columns area const idCell = getById('$id'); const actionsCell = headerElement!.querySelector( '[role="cell"][data-column-id="actions"]' @@ -266,6 +270,7 @@ const recalcAll = () => { updateOverlayHeight(); updateOverlayBounds(); + updateColumnHighlight(); }; /** @@ -681,6 +686,93 @@ }; } + const handleGlobalClick = (event: MouseEvent) => { + // check if click is outside spreadsheet header area + const target = event.target as HTMLElement; + if (!target?.closest('[role="rowheader"]')) { + selectedColumnId = null; + previousColumnId = null; // reset so next selection won't slide + } + }; + + const updateColumnHighlight = () => { + if (!spreadsheetContainer || !selectedColumnId) return; + + const headerCell = spreadsheetContainer.querySelector( + `[role="rowheader"] [role="cell"][data-column-id="${selectedColumnId}"]` + ); + + if (!headerCell) return; + + // calculate position similar to columns-range-overlay logic + if (!headerElement || !headerElement.isConnected) { + headerElement = spreadsheetContainer.querySelector('[role="rowheader"]'); + } + + if (!headerElement) return; + + const containerRect = spreadsheetContainer.getBoundingClientRect(); + const cellRect = headerCell.getBoundingClientRect(); + + const left = Math.round(cellRect.left - containerRect.left); + const width = cellRect.width; + + spreadsheetContainer.style.setProperty('--highlight-left', `${left - 2}px`); + spreadsheetContainer.style.setProperty('--highlight-width', `${width + 2}px`); + }; + + $effect(() => { + if (!spreadsheetContainer) return; + + // remove existing hide-border classes + const hiddenCells = spreadsheetContainer.querySelectorAll('[role="cell"].hide-border'); + hiddenCells.forEach((cell) => cell.classList.remove('hide-border')); + + if (!selectedColumnId) return; + + // hide borders for selected column and previous column + const selectedCells = spreadsheetContainer.querySelectorAll( + `[role="cell"][data-column-id="${selectedColumnId}"]` + ); + + selectedCells.forEach((cell) => cell.classList.add('hide-border')); + + // find and hide previous column's borders (which create the left edge of selected column) + const allHeaders = Array.from( + spreadsheetContainer.querySelectorAll( + '[role="rowheader"] [role="cell"][data-column-id]' + ) + ); + const selectedIndex = allHeaders.findIndex( + (cell) => cell.getAttribute('data-column-id') === selectedColumnId + ); + + if (selectedIndex > 0) { + const prevColumnId = allHeaders[selectedIndex - 1].getAttribute('data-column-id'); + if (prevColumnId) { + const previousCells = spreadsheetContainer.querySelectorAll( + `[role="cell"][data-column-id="${prevColumnId}"]` + ); + previousCells.forEach((cell) => cell.classList.add('hide-border')); + } + } + + // update position + updateColumnHighlight(); + + // track for next selection - + // but only if we had a `real` previous selection + if (previousColumnId !== null) { + previousColumnId = selectedColumnId; + } else { + // fresh after a deselect + // set it for future switches + tick().then(() => { + previousColumnId = selectedColumnId; + }) + } + }); + onDestroy(() => { resizeObserver?.disconnect(); hScroller?.removeEventListener('scroll', recalcAllThrottled); @@ -693,7 +785,7 @@ }); - +
0} class:thinking={$tableColumnSuggestions.thinking || creatingColumns}>
+ + + {#if selectedColumnId} +
+
+ {/if}
@@ -729,9 +833,9 @@ {:else} {@const columnObj = getColumn(column.id)} - {@const columnIcon = basicColumnOptions.find( + {@const columnIconColor = !columnObj?.type ? '--non-overlay-icon-color' : '--overlay-icon-color'} @@ -740,12 +844,16 @@ + onShowStateChanged={onPopoverShowStateChanged} + onChildrenClick={() => { + if (isColumnInteractable && !$isTabletViewport) { + selectedColumnId = column.id; + } + }}> {#snippet children(toggle)} { // tablet viewport check because context-menu @@ -839,14 +947,14 @@ required bind:value={columnObj.key} pattern="^[A-Za-z0-9][A-Za-z0-9._\-]*$"> - +
{/if} @@ -1026,6 +1134,36 @@ } } + .column-highlight-overlay { + opacity: 0; + z-index: 10; + position: absolute; + pointer-events: none; + animation: fadeIn 0.2s ease-out forwards; + border-radius: var(--border-radius-s, 4px); + border: var(--border-width-l, 2px) solid rgba(253, 54, 110, 0.6); + + &.slide { + transition: + left 0.3s ease-out, + width 0.3s ease-out; + } + } + + @keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + /* Hide selected column borders when overlay is active - targeted via JS */ + & :global([role='cell'].hide-border .column-resizer-disabled) { + display: none !important; + } + .columns-range-overlay { position: absolute; left: var(--group-left, 0px); @@ -1082,11 +1220,11 @@ & .floating-action-wrapper { & :global(:first-child) { z-index: 21; - left: calc(65% - 525px / 2); + left: calc(65% - 480px / 2); transition: all 600ms cubic-bezier(0.4, 0, 0.2, 1); @media (max-width: 1024px) { - left: calc(50% - 525px / 2); + left: calc(50% - 480px / 2); } @media (max-width: 768px) { @@ -1096,11 +1234,11 @@ } &.expanded :global(:first-child) { - left: calc(60% - 525px / 2); - max-width: 525px !important; + left: calc(60% - 480px / 2); + max-width: 480px !important; @media (max-width: 1024px) { - left: calc(50% - 525px / 2); + left: calc(50% - 480px / 2); } @media (max-width: 768px) { @@ -1110,7 +1248,7 @@ } &.creating-columns :global(:first-child) { - left: calc(67.5% - 525px / 2); + left: calc(67.5% - 480px / 2); max-width: 300px !important; @media (max-width: 1024px) { diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte index 9f6ca1691a..ce4827dbad 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte @@ -9,13 +9,15 @@ tooltipChildren, toggleOnTapClick = true, onShowStateChanged = null, - enabled = true + enabled = true, + onChildrenClick }: { children: Snippet<[toggle: (event: Event) => void]>; tooltipChildren: Snippet<[toggle: (event: Event) => void]>; toggleOnTapClick?: boolean; onShowStateChanged?: (showing: boolean) => void; enabled?: boolean; + onChildrenClick?: () => void; } = $props(); let showSheet = $state(false); @@ -36,7 +38,7 @@ {@render children(() => (showSheet = false))} {:else} - {/if} From 106b529f0534adee443f2c31bb2b7e760ebd3a82 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 2 Oct 2025 13:22:17 +0530 Subject: [PATCH 03/47] lint. --- .../database-[database]/(suggestions)/empty.svelte | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index b61a8b3038..919033bf7e 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -769,7 +769,7 @@ // set it for future switches tick().then(() => { previousColumnId = selectedColumnId; - }) + }); } }); @@ -1143,11 +1143,11 @@ border-radius: var(--border-radius-s, 4px); border: var(--border-width-l, 2px) solid rgba(253, 54, 110, 0.6); - &.slide { - transition: + &.slide { + transition: left 0.3s ease-out, width 0.3s ease-out; - } + } } @keyframes fadeIn { From c4c7472bca8a17f5db514b603d5cb053b441816e Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 2 Oct 2025 13:24:03 +0530 Subject: [PATCH 04/47] fix: previousColumnId setter. --- .../databases/database-[database]/(suggestions)/empty.svelte | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 919033bf7e..5563fb27e1 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -767,9 +767,7 @@ } else { // fresh after a deselect // set it for future switches - tick().then(() => { - previousColumnId = selectedColumnId; - }); + setTimeout(() => previousColumnId = selectedColumnId, 25); } }); From dec5acdef68b3170780663ee8766f8b189461bd1 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 2 Oct 2025 18:15:17 +0530 Subject: [PATCH 05/47] add: delete support as per new designs. --- .../(suggestions)/empty.svelte | 235 +++++++++++++++--- 1 file changed, 194 insertions(+), 41 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 5563fb27e1..36f81b1bb3 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -8,7 +8,8 @@ Spreadsheet, Typography, FloatingActionBar, - Popover + Popover, + Badge } from '@appwrite.io/pink-svelte'; import { IconFingerPrint, IconPlus } from '@appwrite.io/pink-icons-svelte'; import { isSmallViewport, isTabletViewport } from '$lib/stores/viewport'; @@ -60,6 +61,7 @@ let creatingColumns = $state(false); let selectedColumnId = $state(null); + let selectedColumnName = $state(null); let previousColumnId = $state(null); const baseColProps = { draggable: false, resizable: false }; @@ -262,11 +264,44 @@ directAccessScroller.scrollTo({ left: Math.max(0, scrollLeft), - behavior: 'smooth' + behavior: 'instant', }); } }; + function updateColumnHighlight() { + if (!spreadsheetContainer || !selectedColumnId) return; + + const headerCell = spreadsheetContainer.querySelector( + `[role="rowheader"] [role="cell"][data-column-id="${selectedColumnId}"]` + ); + + if (!headerCell) return; + + // calculate position similar to columns-range-overlay logic + if (!headerElement || !headerElement.isConnected) { + headerElement = spreadsheetContainer.querySelector('[role="rowheader"]'); + } + + if (!headerElement) return; + + const containerRect = spreadsheetContainer.getBoundingClientRect(); + const cellRect = headerCell.getBoundingClientRect(); + + const left = Math.round(cellRect.left - containerRect.left); + const width = cellRect.width; + + spreadsheetContainer.style.setProperty('--highlight-left', `${left - 2}px`); + spreadsheetContainer.style.setProperty('--highlight-width', `${width + 2}px`); + } + + const handleGlobalClick = (event: MouseEvent) => { + const target = event.target as HTMLElement; + if (!target?.closest('[role="rowheader"]')) { + resetSelectedColumn(); + } + }; + const recalcAll = () => { updateOverlayHeight(); updateOverlayBounds(); @@ -281,6 +316,12 @@ scrollAnimationFrame = requestAnimationFrame(() => { recalcAll(); + + // check if selected column is still visible after scroll + if (selectedColumnId && !isColumnVisible(selectedColumnId)) { + resetSelectedColumn(); + } + scrollAnimationFrame = null; }); }; @@ -384,6 +425,9 @@ $tableColumnSuggestions.context = null; $tableColumnSuggestions.thinking = false; + + // reset selection! + resetSelectedColumn(); } async function suggestColumns() { @@ -497,6 +541,9 @@ hScroller.scrollLeft = currentScrollLeft; } }); + + // reset selection! + resetSelectedColumn(); } function updateColumn(columnId: string, updates: Partial) { @@ -520,6 +567,80 @@ return !['$id', '$createdAt', '$updatedAt', 'actions'].includes(id); } + function resetSelectedColumn() { + selectedColumnId = null; + previousColumnId = null; + selectedColumnName = null; + } + + function isColumnVisible(columnId: string) { + if (!spreadsheetContainer || !hScroller) return true; + + const columnCell = spreadsheetContainer.querySelector( + `[role="rowheader"] [role="cell"][data-column-id="${columnId}"]` + ); + + if (!columnCell) return false; + + const cellRect = columnCell.getBoundingClientRect(); + const scrollerRect = hScroller.getBoundingClientRect(); + + // stickies have 40px width + const STICKY_COLUMN_WIDTH = 40; + + // calculate available viewport bounds (excluding both 40px sticky columns) + const leftBound = scrollerRect.left + STICKY_COLUMN_WIDTH; // Selection column (40px) + const rightBound = scrollerRect.right - STICKY_COLUMN_WIDTH; // Actions column (40px) + + const safetyMargin = 2; + return ( + cellRect.left >= leftBound - safetyMargin && cellRect.right <= rightBound + safetyMargin + ); + } + + function scrollColumnIntoView(columnId: string) { + if (!spreadsheetContainer || !hScroller) return false; + + const columnCell = spreadsheetContainer.querySelector( + `[role="rowheader"] [role="cell"][data-column-id="${columnId}"]` + ); + + if (!columnCell) return false; + + const cellRect = columnCell.getBoundingClientRect(); + const scrollerRect = hScroller.getBoundingClientRect(); + + // calculate scroll needed to center the column in view + const scrollLeft = + hScroller.scrollLeft + + cellRect.left - + scrollerRect.left - + (scrollerRect.width - cellRect.width) / 2; + + hScroller.scrollTo({ + left: Math.max(0, scrollLeft), + behavior: 'smooth', + }); + + return true; + } + + function deleteColumn() { + if (!selectedColumnId) return; + + // remove the selected column from customColumns + const columnIndex = customColumns.findIndex((col) => col.key === selectedColumnId); + if (columnIndex !== -1) { + customColumns = customColumns.filter((_, index) => index !== columnIndex); + } + + // reset selection! + resetSelectedColumn(); + + // recalculate view after deletion + requestAnimationFrame(() => recalcAll()); + } + function showIndexSuggestionsNotification() { // safeguard anyways! if (!isCloud) return; @@ -686,40 +807,17 @@ }; } - const handleGlobalClick = (event: MouseEvent) => { - // check if click is outside spreadsheet header area - const target = event.target as HTMLElement; - if (!target?.closest('[role="rowheader"]')) { - selectedColumnId = null; - previousColumnId = null; // reset so next selection won't slide - } - }; - - const updateColumnHighlight = () => { - if (!spreadsheetContainer || !selectedColumnId) return; - - const headerCell = spreadsheetContainer.querySelector( - `[role="rowheader"] [role="cell"][data-column-id="${selectedColumnId}"]` - ); - - if (!headerCell) return; - - // calculate position similar to columns-range-overlay logic - if (!headerElement || !headerElement.isConnected) { - headerElement = spreadsheetContainer.querySelector('[role="rowheader"]'); + // scroll to view if needed and select! + function selectColumnWithId(column: Column) { + const columnId = column.id; + selectedColumnName = column.title; + if (!isColumnVisible(columnId)) { + scrollColumnIntoView(columnId); + setTimeout(() => (selectedColumnId = columnId), 300); + } else { + selectedColumnId = columnId; } - - if (!headerElement) return; - - const containerRect = spreadsheetContainer.getBoundingClientRect(); - const cellRect = headerCell.getBoundingClientRect(); - - const left = Math.round(cellRect.left - containerRect.left); - const width = cellRect.width; - - spreadsheetContainer.style.setProperty('--highlight-left', `${left - 2}px`); - spreadsheetContainer.style.setProperty('--highlight-width', `${width + 2}px`); - }; + } $effect(() => { if (!spreadsheetContainer) return; @@ -767,7 +865,7 @@ } else { // fresh after a deselect // set it for future switches - setTimeout(() => previousColumnId = selectedColumnId, 25); + setTimeout(() => (previousColumnId = selectedColumnId), 25); } }); @@ -845,7 +943,7 @@ onShowStateChanged={onPopoverShowStateChanged} onChildrenClick={() => { if (isColumnInteractable && !$isTabletViewport) { - selectedColumnId = column.id; + selectColumnWithId(column); } }}> {#snippet children(toggle)} @@ -891,6 +989,7 @@ !$isTabletViewport ) { toggle(event); + resetSelectedColumn(); } }}> {#if !columnObj?.isPlaceholder} @@ -1048,10 +1147,45 @@
{:else if customColumns.some((col) => !col.isPlaceholder) && showFloatingBar} + +
+ + + + + column selected + + + + + + (selectedColumnId = null)}> + Cancel + + !col.isPlaceholder).length <= 1} + on:click={deleteColumn}> + Delete + + + + +
+ +
+ class:creating-columns={creatingColumns} + class:has-selection={selectedColumnId !== null}> @@ -1216,8 +1350,12 @@ } & .floating-action-wrapper { - & :global(:first-child) { - z-index: 21; + // probably limited, but has good support + // for height transition with fit-content and auto, etc. + interpolate-size: allow-keywords; + + & :global(div:first-of-type) { + z-index: 22; left: calc(65% - 480px / 2); transition: all 600ms cubic-bezier(0.4, 0, 0.2, 1); @@ -1231,7 +1369,7 @@ } } - &.expanded :global(:first-child) { + &.expanded :global(div:first-of-type) { left: calc(60% - 480px / 2); max-width: 480px !important; @@ -1245,6 +1383,21 @@ } } + &.expanded.has-selection :global(div:first-of-type) { + height: 44px; + } + + &.selection :global(div:first-of-type) { + z-index: 21; + bottom: 80px; /* oddly specific maybe, but diff as per design */ + height: fit-content; + padding-bottom: 10px; + border-bottom: unset; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + background: var(--bgcolor-neutral-default); + } + &.creating-columns :global(:first-child) { left: calc(67.5% - 480px / 2); max-width: 300px !important; From 963e3e68c5b2d8393eac46aa40d0a8fc5f9a7dfb Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 2 Oct 2025 19:15:25 +0530 Subject: [PATCH 06/47] add: delete for mobile. --- .../(suggestions)/empty.svelte | 86 ++++++++++++------- .../(suggestions)/options.svelte | 7 ++ 2 files changed, 61 insertions(+), 32 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 36f81b1bb3..c07686a99a 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -90,7 +90,7 @@ const updateOverlayHeight = () => { if (!spreadsheetContainer) return; if (!headerElement || !headerElement.isConnected) { - headerElement = spreadsheetContainer.querySelector('[role="rowheader"]'); + headerElement = spreadsheetContainer?.querySelector('[role="rowheader"]'); } if (!headerElement) return; @@ -111,7 +111,7 @@ const updateOverlayBounds = () => { if (!spreadsheetContainer) return; if (!headerElement || !headerElement.isConnected) { - headerElement = spreadsheetContainer.querySelector('[role="rowheader"]'); + headerElement = spreadsheetContainer?.querySelector('[role="rowheader"]'); } if (!headerElement) return; @@ -264,7 +264,7 @@ directAccessScroller.scrollTo({ left: Math.max(0, scrollLeft), - behavior: 'instant', + behavior: 'instant' }); } }; @@ -522,8 +522,7 @@ } } - function onPopoverShowStateChanged(value: boolean) { - showFloatingBar = !value; + async function updateOverlaysForMobile(value: boolean) { if ($isSmallViewport) { setTimeout(() => { [rangeOverlayEl, fadeBottomOverlayEl].forEach((el) => { @@ -533,6 +532,11 @@ }); }, 0); } + } + + function onPopoverShowStateChanged(value: boolean) { + showFloatingBar = !value; + updateOverlaysForMobile(value); const currentScrollLeft = hScroller?.scrollLeft || 0; @@ -619,17 +623,17 @@ hScroller.scrollTo({ left: Math.max(0, scrollLeft), - behavior: 'smooth', + behavior: 'smooth' }); return true; } - function deleteColumn() { - if (!selectedColumnId) return; + function deleteColumn(columnId: string) { + if (!columnId) return; // remove the selected column from customColumns - const columnIndex = customColumns.findIndex((col) => col.key === selectedColumnId); + const columnIndex = customColumns.findIndex((col) => col.key === columnId); if (columnIndex !== -1) { customColumns = customColumns.filter((_, index) => index !== columnIndex); } @@ -637,6 +641,9 @@ // reset selection! resetSelectedColumn(); + // see overlay is visible after deletion on mobile! + setTimeout(() => updateOverlaysForMobile(false), 150); + // recalculate view after deletion requestAnimationFrame(() => recalcAll()); } @@ -828,32 +835,34 @@ if (!selectedColumnId) return; - // hide borders for selected column and previous column - const selectedCells = spreadsheetContainer.querySelectorAll( - `[role="cell"][data-column-id="${selectedColumnId}"]` - ); + setTimeout(() => { + // hide borders for selected column and previous column + const selectedCells = spreadsheetContainer.querySelectorAll( + `[role="cell"][data-column-id="${selectedColumnId}"]` + ); - selectedCells.forEach((cell) => cell.classList.add('hide-border')); + selectedCells.forEach((cell) => cell.classList.add('hide-border')); - // find and hide previous column's borders (which create the left edge of selected column) - const allHeaders = Array.from( - spreadsheetContainer.querySelectorAll( - '[role="rowheader"] [role="cell"][data-column-id]' - ) - ); - const selectedIndex = allHeaders.findIndex( - (cell) => cell.getAttribute('data-column-id') === selectedColumnId - ); + // find and hide previous column's borders (which create the left edge of selected column) + const allHeaders = Array.from( + spreadsheetContainer.querySelectorAll( + '[role="rowheader"] [role="cell"][data-column-id]' + ) + ); + const selectedIndex = allHeaders.findIndex( + (cell) => cell.getAttribute('data-column-id') === selectedColumnId + ); - if (selectedIndex > 0) { - const prevColumnId = allHeaders[selectedIndex - 1].getAttribute('data-column-id'); - if (prevColumnId) { - const previousCells = spreadsheetContainer.querySelectorAll( - `[role="cell"][data-column-id="${prevColumnId}"]` - ); - previousCells.forEach((cell) => cell.classList.add('hide-border')); + if (selectedIndex > 0) { + const prevColumnId = allHeaders[selectedIndex - 1].getAttribute('data-column-id'); + if (prevColumnId) { + const previousCells = spreadsheetContainer.querySelectorAll( + `[role="cell"][data-column-id="${prevColumnId}"]` + ); + previousCells.forEach((cell) => cell.classList.add('hide-border')); + } } - } + }, 300); // update position updateColumnHighlight(); @@ -1109,6 +1118,19 @@ {/if} {/snippet} + + {#snippet mobileFooterChildren(toggle)} + { + toggle(event); + deleteColumn(column.id); + }} + style="position: absolute; left: 1rem;" + >Delete + + {/snippet} {/if} {/each} @@ -1172,7 +1194,7 @@ size="xs" variant="secondary" disabled={customColumns.filter((col) => !col.isPlaceholder).length <= 1} - on:click={deleteColumn}> + on:click={() => deleteColumn(selectedColumnName)}> Delete diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte index ce4827dbad..22b576b83e 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/options.svelte @@ -7,6 +7,7 @@ let { children, tooltipChildren, + mobileFooterChildren, toggleOnTapClick = true, onShowStateChanged = null, enabled = true, @@ -14,6 +15,7 @@ }: { children: Snippet<[toggle: (event: Event) => void]>; tooltipChildren: Snippet<[toggle: (event: Event) => void]>; + mobileFooterChildren?: Snippet<[toggle: (event: Event) => void]>; toggleOnTapClick?: boolean; onShowStateChanged?: (showing: boolean) => void; enabled?: boolean; @@ -58,6 +60,11 @@ showSheet = false; } }}> + + {#snippet footer()} + {@render mobileFooterChildren?.(() => (showSheet = false))} + {/snippet} + {@render tooltipChildren(() => (showSheet = false))} {/if} From d45599e1609d9c2c1305a700e562e53e6f94a255 Mon Sep 17 00:00:00 2001 From: Darshan Date: Fri, 3 Oct 2025 09:31:55 +0530 Subject: [PATCH 07/47] add: menu for inner icon as well. --- .../(suggestions)/empty.svelte | 164 ++++++++++-------- .../(suggestions)/options.svelte | 1 - 2 files changed, 88 insertions(+), 77 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index c07686a99a..28cc36df7b 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -574,7 +574,7 @@ function resetSelectedColumn() { selectedColumnId = null; previousColumnId = null; - selectedColumnName = null; + /*selectedColumnName = null;*/ } function isColumnVisible(columnId: string) { @@ -677,6 +677,16 @@ creatingColumns = true; const client = sdk.forProject(page.params.region, page.params.project); + const isAnyEmpty = customColumns.some((col) => !col.key); + if (isAnyEmpty) { + creatingColumns = false; + addNotification({ + type: 'warning', + message: 'Some columns have invalid keys' + }); + return; + } + try { const results = []; @@ -938,9 +948,9 @@ {:else} {@const columnObj = getColumn(column.id)} - + )?.icon} {@const columnIconColor = !columnObj?.type ? '--non-overlay-icon-color' : '--overlay-icon-color'} @@ -979,88 +989,41 @@ {column.title} - -
- { - if ( - isColumnInteractable && - !$isTabletViewport - ) { - toggle(event); - resetSelectedColumn(); - } - }}> - {#if !columnObj?.isPlaceholder} - - {/if} - -
- -
- - - {#each basicColumnOptions as option} - { - toggle(); - updateColumn(column.id, { - type: option.type, - format: - option.format || null - }); - }}> - - - {option.name} - - - {/each} - - -
-
+ {@render changeColumnTypePopover({ + id: column.id, + columnObj, + iconColor: columnIconColor, + icon: column.icon, + isColumnInteractable, + index + })} {#if !$isTabletViewport} -
+
- +
{/if} @@ -1256,6 +1219,55 @@ {/if}
+{#snippet changeColumnTypePopover({ id, columnObj, iconColor, icon, isColumnInteractable, index })} + +
+ { + if (isColumnInteractable && !$isTabletViewport) { + toggle(event); + resetSelectedColumn(); + } + }}> + {#if !columnObj?.isPlaceholder} + + {/if} + +
+ +
+ + + {#each basicColumnOptions as option} + { + toggle(); + updateColumn(id, { + type: option.type, + format: option.format || null + }); + }}> + + + {option.name} + + + {/each} + + +
+
+{/snippet} + From 05d86898013b9b5fb9c35044ee2ae916aa3895c9 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 6 Oct 2025 16:27:52 +0530 Subject: [PATCH 10/47] update: widths. --- .../table-[table]/indexes/+page.svelte | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte index ffdb00d27a..08c138cf80 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte @@ -65,14 +65,14 @@ const spreadsheetColumns = $derived([ { id: 'key', - width: getColumnWidth('key', $isSmallViewport ? 250 : 200), - minimumWidth: $isSmallViewport ? 250 : 200, + width: getColumnWidth('key', 250), + minimumWidth: 250, resizable: true }, { id: 'type', - width: getColumnWidth('type', 120), - minimumWidth: 120, + width: getColumnWidth('type', 200), + minimumWidth: 200, resizable: true }, { From 9ec11dc9bb3f9da1374c141b8daa93ff8d3b0010 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 6 Oct 2025 17:17:51 +0530 Subject: [PATCH 11/47] update: columns ai suggestions [wip]. --- src/lib/elements/forms/inputLine.svelte | 11 +++- src/lib/elements/forms/inputPoint.svelte | 7 ++- src/lib/elements/forms/inputPolygon.svelte | 5 +- .../table-[table]/columns/boolean.svelte | 10 ++- .../table-[table]/columns/datetime.svelte | 14 +++-- .../table-[table]/columns/email.svelte | 14 +++-- .../table-[table]/columns/enum.svelte | 17 ++--- .../table-[table]/columns/float.svelte | 18 ++++-- .../table-[table]/columns/integer.svelte | 21 ++++--- .../table-[table]/columns/ip.svelte | 9 ++- .../table-[table]/columns/line.svelte | 15 ++++- .../table-[table]/columns/point.svelte | 15 ++++- .../table-[table]/columns/polygon.svelte | 15 ++++- .../table-[table]/columns/relationship.svelte | 14 +++-- .../table-[table]/columns/string.svelte | 18 +++--- .../table-[table]/columns/url.svelte | 16 ++--- .../table-[table]/createColumn.svelte | 63 ++++++++++++++++++- 17 files changed, 208 insertions(+), 74 deletions(-) diff --git a/src/lib/elements/forms/inputLine.svelte b/src/lib/elements/forms/inputLine.svelte index 3987b3635b..6bfeb0fe2e 100644 --- a/src/lib/elements/forms/inputLine.svelte +++ b/src/lib/elements/forms/inputLine.svelte @@ -14,6 +14,7 @@ onDeletePoint: (index: number) => void; onChangePoint: (pointIndex: number, coordIndex: number, newValue: number) => void; addLineButton?: Snippet; + disabled?: boolean; }; let { @@ -24,7 +25,8 @@ onAddPoint, onDeletePoint, onChangePoint, - addLineButton + addLineButton, + disabled }: Props = $props(); function isDeleteDisabled(index: number) { @@ -40,6 +42,7 @@ {#each values as value, index} - {@render addLineButton?.()} diff --git a/src/lib/elements/forms/inputPoint.svelte b/src/lib/elements/forms/inputPoint.svelte index 4c0b4ce40f..9a3f70183e 100644 --- a/src/lib/elements/forms/inputPoint.svelte +++ b/src/lib/elements/forms/inputPoint.svelte @@ -10,6 +10,7 @@ deletePoints?: boolean; onDeletePoint?: () => void; disableDelete?: boolean; + disabled?: boolean; onChangePoint: (index: number, newValue: number) => void; } @@ -21,7 +22,8 @@ deletePoints = false, disableDelete = false, onDeletePoint, - onChangePoint + onChangePoint, + disabled }: Props = $props(); @@ -38,6 +40,7 @@ placeholder="Enter value" step={0.0001} value={values[index]} + {disabled} on:change={(e) => onChangePoint(index, Number.parseFloat(`${e.detail}`))} /> {/each} {/if} @@ -45,7 +48,7 @@ diff --git a/src/lib/elements/forms/inputPolygon.svelte b/src/lib/elements/forms/inputPolygon.svelte index c2bcbb4db1..766dfa7d1b 100644 --- a/src/lib/elements/forms/inputPolygon.svelte +++ b/src/lib/elements/forms/inputPolygon.svelte @@ -17,6 +17,7 @@ coordIndex: number, newValue: number ) => void; + disabled?: boolean; }; let { @@ -26,7 +27,8 @@ onAddPoint, onAddLine, onDeletePoint, - onChangePoint + onChangePoint, + disabled }: Props = $props(); @@ -34,6 +36,7 @@ {#each values as value, index} onAddPoint(index)} {nullable} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/boolean.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/boolean.svelte index cd09096a4e..83e919630f 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/boolean.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/boolean.svelte @@ -39,6 +39,7 @@ import { InputSelect } from '$lib/elements/forms'; export let editing = false; + export let disabled = false; export let data: Partial = { required: false, array: false, @@ -67,6 +68,7 @@ array: false, ...data }); + $: listen(data); $: handleDefaultState($required || $array); @@ -76,24 +78,26 @@ id="default" label="Default value" placeholder="Select a value" - disabled={data.required || data.array} + disabled={data.required || data.array || disabled} options={[ { label: 'NULL', value: null }, { label: 'True', value: true }, { label: 'False', value: false } ]} bind:value={data.default} /> + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/datetime.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/datetime.svelte index 827d77798b..5ef5afca14 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/datetime.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/datetime.svelte @@ -42,13 +42,13 @@ + {#if isSuggestionsFeatureEnabled} + + {/if} + @@ -195,6 +248,7 @@ id="type" label="Type" bind:value={selectedOption} + disabled={isSuggestionsEnabled} options={columnOptions.map((attr) => { return { label: attr.name, @@ -206,6 +260,9 @@ {#if selectedOption} - ($option = null)} /> + ($option = null)} /> {/if} From bd26eeaab14c7922eb109777a9a8b355ef08c689 Mon Sep 17 00:00:00 2001 From: Darshan Date: Wed, 8 Oct 2025 10:22:53 +0530 Subject: [PATCH 12/47] update: smoother slides. --- .../database-[database]/(suggestions)/empty.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 04923f1ece..a7a39faf93 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -1133,7 +1133,7 @@
{#each Array.from({ length: emptyCells }) as _} - + {#each spreadsheetColumns as column} {@const columnObj = getColumn(column.id)} {@const isColumnInteractable = @@ -1365,8 +1365,8 @@ &.slide { transition: - left 0.3s ease-out, - width 0.3s ease-out; + left 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94), + width 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); } } From d492a0ae447d335828990cf50189aa2bf4d383d1 Mon Sep 17 00:00:00 2001 From: Darshan Date: Wed, 8 Oct 2025 13:16:26 +0530 Subject: [PATCH 13/47] new: empty states. --- src/lib/components/card.svelte | 22 +++- .../(suggestions)/empty.svelte | 4 +- .../table-[table]/+page.svelte | 104 ++++++++++++------ .../table-[table]/indexes/+page.svelte | 66 ++++++----- .../table-[table]/layout/emptySheet.svelte | 83 ++++---------- .../layout/emptySheetCards.svelte | 48 ++++++++ 6 files changed, 195 insertions(+), 132 deletions(-) create mode 100644 src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheetCards.svelte diff --git a/src/lib/components/card.svelte b/src/lib/components/card.svelte index fd94436ab9..c21c90ef55 100644 --- a/src/lib/components/card.svelte +++ b/src/lib/components/card.svelte @@ -20,21 +20,23 @@ }; type ButtonProps = { - isButton: true; + isButton: boolean; href?: never; }; type AnchorProps = { href: string; - isButton?: never; + isButton?: boolean; + external?: boolean; }; + let classes = ''; type $$Props = BaseProps & (ButtonProps | AnchorProps | BaseProps) & BaseCardProps; - export let isDashed = false; - export let isButton = false; + export let isDashed: boolean = false; + export let isButton: boolean = false; export let href: string = null; - let classes = ''; + export let external: boolean = false; export { classes as class }; export let style = ''; export let padding: $$Props['padding'] = 'm'; @@ -45,7 +47,15 @@ {#if href} - + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index a7a39faf93..aeeb58ead7 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -1365,8 +1365,8 @@ &.slide { transition: - left 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94), - width 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); + left 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94), + width 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); } } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte index df77376faa..45e3d7f3fe 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte @@ -26,13 +26,21 @@ import { addNotification } from '$lib/stores/notifications'; import { Click, Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { isSmallViewport } from '$lib/stores/viewport'; - import { IconChevronDown, IconChevronUp, IconPlus } from '@appwrite.io/pink-icons-svelte'; + import { + IconBookOpen, + IconChevronDown, + IconChevronUp, + IconPlus, + IconViewBoards + } from '@appwrite.io/pink-icons-svelte'; import type { Models } from '@appwrite.io/console'; import EmptySheet from './layout/emptySheet.svelte'; import CreateRow from './rows/create.svelte'; import { onDestroy } from 'svelte'; import { isCloud } from '$lib/system'; import { Empty as SuggestionsEmptySheet, tableColumnSuggestions } from '../(suggestions)'; + import EmptySheetCards from './layout/emptySheetCards.svelte'; + import IconAI from '../(suggestions)/icon/aiForButton.svelte'; export let data: PageData; @@ -201,58 +209,82 @@ { + customColumns={createTableColumns($table.columns, selected)}> + {#snippet actions()} + + {/snippet} + {:else} { + customColumns={createTableColumns($table.columns, selected)}> + {#snippet actions()} + { $showRowCreateSheet.show = true; - } - }, - random: { - onClick: () => { + }} /> + + { $randomDataModalState.show = true; - } - } - }} /> + }} /> + {/snippet} + {/if} {:else if isCloud && canShowSuggestionsSheet} {:else} - { + + {#snippet actions()} + { $showCreateColumnSheet.show = true; - } - }, - random: { - onClick: () => { + }} /> + + { + // todo: add a modal and show input, no toggle. + }} /> + + { $randomDataModalState.show = true; - } - } - }} /> + }} /> + + + {/snippet} + {/if}
{/key} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte index 08c138cf80..2db12152fd 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte @@ -39,6 +39,7 @@ import { page } from '$app/state'; import { showIndexesSuggestions } from '../../(suggestions)'; import IconAI from '../../(suggestions)/icon/aiForButton.svelte'; + import EmptySheetCards from '$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheetCards.svelte'; let { data @@ -289,22 +290,7 @@ {:else} - showIndexesSuggestions.update(() => true), - disabled: !$table?.columns?.length - }, - secondary: { - icon: IconPlus, - text: 'Create index', - onClick: () => (showCreateIndex = true), - disabled: !$table?.columns?.length - } - }}> + {#snippet subtitle()} Create indexes to improve query and sorting performance. Learn more in the @@ -315,20 +301,48 @@ {/snippet} + + {#snippet actions()} + { + showIndexesSuggestions.update(() => true); + }} /> + + { + showIndexesSuggestions.update(() => true); + }} /> + {/snippet} {/if} {:else} - { + + {#snippet actions()} + { $showCreateColumnSheet.show = true; - } - } - }} /> + }} /> + + { + // TODO: add a modal and show input, no toggle. + }} /> + {/snippet} + {/if} {#if selectedIndexes.length > 0} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte index 4ed7b10366..bba48ed0c9 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheet.svelte @@ -19,36 +19,26 @@ expandTabs } from '../store'; import SpreadsheetContainer from './spreadsheet.svelte'; - import { type ComponentType, onDestroy, onMount, type Snippet } from 'svelte'; + import { onDestroy, onMount, type Snippet } from 'svelte'; import { debounce } from '$lib/helpers/debounce'; import { columnOptions } from '../columns/store'; type Mode = 'rows' | 'rows-filtered' | 'indexes'; - interface Action { - text?: string; - disabled?: boolean; - onClick?: () => void; - icon?: ComponentType; - } - const { mode, - showActions = true, customColumns = [], title, subtitle, - actions + actions, + showActions } = $props<{ mode: Mode; - showActions?: boolean; customColumns?: Column[]; title?: string; subtitle?: Snippet; - actions?: { - primary?: Action; - secondary?: Action; - }; + actions?: Snippet; + showActions?: boolean; }>(); let spreadsheetContainer: HTMLElement; @@ -250,7 +240,7 @@ return columns; }; - const spreadsheetColumns = $derived(mode === 'rows' ? getRowColumns() : getIndexesColumns()); + const spreadsheetColumns = $derived(mode === 'indexes' ? getIndexesColumns() : getRowColumns()); const emptyCells = $derived( ($isSmallViewport ? 14 : $isTabletViewport ? 17 : 24) + (!$expandTabs ? 2 : 0) @@ -344,58 +334,22 @@ gap="xl" alignItems="center" alignContent="center" - style="max-width: 353px"> + style="width: 653px; max-width: {$isSmallViewport ? '353px' : undefined}"> {title ?? `You have no ${mode} yet`} {@render subtitle?.()} - {#if showActions} - - {#if mode !== 'rows-filtered'} - - {@const icon = actions?.primary?.icon ?? IconPlus} - - - - {actions?.primary?.text ?? `Create ${mode}`} - - - {#if mode === 'rows' || mode === 'indexes'} - - {#if actions?.secondary?.icon} - - {/if} - - {actions?.secondary?.text ?? `Generate sample data`} - - {/if} + {#if showActions && actions} + {@const inline = mode === 'rows-filtered'} + + {#if inline} + {@render actions?.()} {:else} - - {#if actions?.primary?.icon} - - {/if} - - {actions?.primary?.text} - + + {@render actions?.()} + {/if} {/if} @@ -490,7 +444,12 @@ } .empty-actions { - margin-bottom: 8%; + margin-bottom: 10%; pointer-events: auto; + + @media (max-width: 1024px) { + // experiment + margin-bottom: 15%; + } } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheetCards.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheetCards.svelte new file mode 100644 index 0000000000..f38edeb62f --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheetCards.svelte @@ -0,0 +1,48 @@ + + + onClick?.()}> + + {#if icon} + + {/if} + + + + {title} + + {#if subtitle} + + {subtitle} + + {/if} + + + From 00b15cd5b072b73a3b2f485e96f3d41851990b72 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 19 Oct 2025 15:21:01 +0530 Subject: [PATCH 14/47] update: design comments. --- .../databases/database-[database]/(suggestions)/empty.svelte | 4 ++-- .../database-[database]/table-[table]/createColumn.svelte | 2 +- .../database-[database]/table-[table]/indexes/+page.svelte | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index aeeb58ead7..40c8e53ce2 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -1543,7 +1543,7 @@ background: linear-gradient( 180deg, rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 0.86) 32.25%, + rgba(255, 255, 255, 0.86) 85%, /* show more of the bottom area */ #fff 100% ); z-index: 20; /* under overlay */ @@ -1558,7 +1558,7 @@ background: linear-gradient( 180deg, rgba(29, 29, 33, 0) 0%, - rgba(29, 29, 33, 0.86) 21%, + rgba(29, 29, 33, 0.86) 85%, /* show more of the bottom area */ #1d1d21 100% ); } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte index 5d6e3ee554..9b54eeb0a3 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte @@ -38,7 +38,7 @@ const databaseId = page.params.database; // flow isn't complete yet! - const isSuggestionsFeatureEnabled = false; + const isSuggestionsFeatureEnabled = true; let key: string = $state(column?.key ?? null); let data: Partial = $state({ diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte index 2db12152fd..a425ed44a1 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte @@ -293,7 +293,7 @@ {#snippet subtitle()} - Create indexes to improve query and sorting performance. Learn more in the + Need a hand? Learn more in the From 2f6346f931b485cd71beb7b0c277b4d1206698a8 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 19 Oct 2025 16:57:09 +0530 Subject: [PATCH 15/47] feat: undo delete. --- .../(suggestions)/empty.svelte | 141 ++++++++++++++---- 1 file changed, 115 insertions(+), 26 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 40c8e53ce2..3b0178eac4 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -61,11 +61,18 @@ let creatingColumns = $state(false); let selectedColumnId = $state(null); - let selectedColumnName = $state(null); let previousColumnId = $state(null); + let selectedColumnName = $state(null); + + // for deleting a column + undo + let undoTimer: ReturnType | null = $state(null); + let columnBeingDeleted: (SuggestedColumnSchema & { deletedIndex?: number }) | null = + $state(null); + const baseColProps = { draggable: false, resizable: false }; const NOTIFICATION_AND_MOCK_DELAY = 1250; + const COLUMN_DELETION_UNDO_TIMER_LIMIT = 10000; // 10 seconds const getColumnWidth = (columnKey: string) => Math.max(180, columnKey.length * 8 + 60); const safeNumericValue = (value: number | undefined) => @@ -662,12 +669,37 @@ function deleteColumn(columnId: string) { if (!columnId) return; - // remove the selected column from customColumns - const columnIndex = customColumns.findIndex((col) => col.key === columnId); + let columnIndex = -1; + let columnSchema: SuggestedColumnSchema; + + for (let index = 0; index < customColumns.length; index++) { + if (customColumns[index].key === columnId) { + columnIndex = index; + columnSchema = customColumns[index]; + break; + } + } + if (columnIndex !== -1) { - customColumns = customColumns.filter((_, index) => index !== columnIndex); + customColumns.splice(columnIndex, 1); + } + + // store column with its index for undo + columnBeingDeleted = { ...columnSchema, deletedIndex: columnIndex }; + + // clear any existing timer + if (undoTimer) { + clearTimeout(undoTimer); } + // start 10-second undo timer + undoTimer = setTimeout(() => { + undoTimer = null; + selectedColumnId = null; + columnBeingDeleted = null; + selectedColumnName = null; + }, COLUMN_DELETION_UNDO_TIMER_LIMIT); + // reset selection! resetSelectedColumn(); @@ -678,6 +710,39 @@ requestAnimationFrame(() => recalcAll()); } + function undoDelete() { + if (!columnBeingDeleted) return; + + const { deletedIndex, ...columnData } = columnBeingDeleted; + + // restore column at its original index + if (deletedIndex !== undefined && deletedIndex >= 0) { + customColumns.splice(deletedIndex, 0, columnData); + } else { + // fallback: add at the end if index is missing + customColumns.push(columnData); + } + + // clear undo state + columnBeingDeleted = null; + + // clear timer + if (undoTimer) { + clearTimeout(undoTimer); + undoTimer = null; + } + + // recalculate view after restore + requestAnimationFrame(() => { + recalcAll(); + + tick().then(() => { + selectedColumnId = columnData.key; + selectedColumnName = columnData.key; + }) + }); + } + function showIndexSuggestionsNotification() { // safeguard anyways! if (!isCloud) return; @@ -864,11 +929,9 @@ } else { selectedColumnId = columnId; } - } - $effect(() => { - console.log('selectedColumnId changed:', selectedColumnId); - }); + columnBeingDeleted = null; + } $effect(() => { if (!spreadsheetContainer) return; @@ -1185,33 +1248,59 @@ {:else if customColumns.some((col) => !col.isPlaceholder) && showFloatingBar} - -
+ + {@const isUndoDeleteMode = columnBeingDeleted && columnBeingDeleted?.key !== null} + {@const columnName = isUndoDeleteMode ? columnBeingDeleted?.key : selectedColumnName} + + {@const hasSelection = selectedColumnId !== null || isUndoDeleteMode} +
- - column selected + + + {#if isUndoDeleteMode} + was deleted. You can undo this action. + {:else} + column selected + {/if} - (selectedColumnId = null)}> - Cancel - + {#if !isUndoDeleteMode} + (selectedColumnId = null)}> + Cancel + + {/if} !col.isPlaceholder).length <= 1} - on:click={() => deleteColumn(selectedColumnName)}> - Delete + disabled={!isUndoDeleteMode && + customColumns.filter((col) => !col.isPlaceholder).length <= 1} + on:click={() => { + if (isUndoDeleteMode) { + undoDelete(); + } else { + deleteColumn(selectedColumnName); + } + }}> + {#if isUndoDeleteMode} + Undo + {:else} + Delete + {/if} @@ -1223,7 +1312,7 @@ class="floating-action-wrapper" class:expanded={!creatingColumns} class:creating-columns={creatingColumns} - class:has-selection={selectedColumnId !== null}> + class:has-selection={hasSelection}> @@ -1543,8 +1632,8 @@ background: linear-gradient( 180deg, rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 0.86) 85%, /* show more of the bottom area */ - #fff 100% + rgba(255, 255, 255, 0.86) 85%, + /* show more of the bottom area */ #fff 100% ); z-index: 20; /* under overlay */ display: flex; @@ -1558,8 +1647,8 @@ background: linear-gradient( 180deg, rgba(29, 29, 33, 0) 0%, - rgba(29, 29, 33, 0.86) 85%, /* show more of the bottom area */ - #1d1d21 100% + rgba(29, 29, 33, 0.86) 85%, + /* show more of the bottom area */ #1d1d21 100% ); } From f3457e67317e23180a98c894baa11b87aeda5bc7 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 19 Oct 2025 17:00:36 +0530 Subject: [PATCH 16/47] fix: expanded fab shown when creating columns. --- .../(suggestions)/empty.svelte | 100 +++++++++--------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 3b0178eac4..4d65ea8c6c 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -1251,61 +1251,63 @@ {@const isUndoDeleteMode = columnBeingDeleted && columnBeingDeleted?.key !== null} {@const columnName = isUndoDeleteMode ? columnBeingDeleted?.key : selectedColumnName} - {@const hasSelection = selectedColumnId !== null || isUndoDeleteMode} -
- - - - - - {#if isUndoDeleteMode} - was deleted. You can undo this action. - {:else} - column selected - {/if} - - - - - {#if !isUndoDeleteMode} - + + + + (selectedColumnId = null)}> - Cancel - - {/if} - !col.isPlaceholder).length <= 1} - on:click={() => { - if (isUndoDeleteMode) { - undoDelete(); - } else { - deleteColumn(selectedColumnName); - } - }}> + variant="secondary" + content={columnName} + type={isUndoDeleteMode ? 'error' : undefined} /> + {#if isUndoDeleteMode} - Undo + was deleted. You can undo this action. {:else} - Delete + column selected {/if} - - - - -
+ +
+ + + + {#if !isUndoDeleteMode} + (selectedColumnId = null)}> + Cancel + + {/if} + !col.isPlaceholder).length <= 1} + on:click={() => { + if (isUndoDeleteMode) { + undoDelete(); + } else { + deleteColumn(selectedColumnName); + } + }}> + {#if isUndoDeleteMode} + Undo + {:else} + Delete + {/if} + + + +
+
+ {/if}
Date: Sun, 19 Oct 2025 19:05:07 +0530 Subject: [PATCH 17/47] feat: column suggestions modal. --- package.json | 4 +- pnpm-lock.yaml | 20 ++-- .../(suggestions)/columns.svelte | 62 +++++++++++++ .../(suggestions)/empty.svelte | 14 ++- .../(suggestions)/input.svelte | 12 ++- .../(suggestions)/store.ts | 3 + .../table-[table]/+layout.svelte | 9 +- .../table-[table]/+page.svelte | 12 ++- .../table-[table]/createColumn.svelte | 93 ++++++++----------- .../table-[table]/indexes/+page.svelte | 6 +- 10 files changed, 156 insertions(+), 79 deletions(-) create mode 100644 src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte diff --git a/package.json b/package.json index fa064b99f6..1cf4a182aa 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,9 @@ "@ai-sdk/svelte": "^1.1.24", "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@636ed39", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@754a996", + "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@6faeea0", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@754a996", + "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@6faeea0", "@faker-js/faker": "^9.9.0", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 75e232a56c..38cad3b40c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,14 +18,14 @@ importers: specifier: 0.25.0 version: 0.25.0 '@appwrite.io/pink-icons-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@754a996 - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@754a996(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@6faeea0 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@6faeea0(svelte@5.25.3) '@appwrite.io/pink-legacy': specifier: ^1.0.3 version: 1.0.3 '@appwrite.io/pink-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@754a996 - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@754a996(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@6faeea0 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@6faeea0(svelte@5.25.3) '@faker-js/faker': specifier: ^9.9.0 version: 9.9.0 @@ -269,8 +269,8 @@ packages: peerDependencies: svelte: ^4.0.0 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@754a996': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@754a996} + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@6faeea0': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@6faeea0} version: 2.0.0-RC.1 peerDependencies: svelte: ^4.0.0 @@ -284,8 +284,8 @@ packages: '@appwrite.io/pink-legacy@1.0.3': resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==} - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@754a996': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@754a996} + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@6faeea0': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@6faeea0} version: 2.0.0-RC.2 peerDependencies: svelte: ^4.0.0 @@ -3709,7 +3709,7 @@ snapshots: dependencies: svelte: 5.25.3 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@754a996(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@6faeea0(svelte@5.25.3)': dependencies: svelte: 5.25.3 @@ -3722,7 +3722,7 @@ snapshots: '@appwrite.io/pink-icons': 1.0.0 the-new-css-reset: 1.11.3 - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@754a996(svelte@5.25.3)': + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@6faeea0(svelte@5.25.3)': dependencies: '@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3) '@floating-ui/dom': 1.6.13 diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte new file mode 100644 index 0000000000..9cbea3a2aa --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte @@ -0,0 +1,62 @@ + + + + + + + + + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 4d65ea8c6c..8e9fa2dfeb 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -43,6 +43,12 @@ import IconAINotification from './icon/aiNotification.svelte'; + let { + userColumns = [] + }: { + userColumns?: Column[]; + } = $props(); + let resizeObserver: ResizeObserver; let spreadsheetContainer: HTMLElement; @@ -394,6 +400,7 @@ ...baseColProps }, ...finalCustomColumns, + /*...userColumns,*/ { id: 'actions', title: '', @@ -409,6 +416,8 @@ const emptyCells = $derived(($isSmallViewport ? 14 : 17) + (!$expandTabs ? 2 : 0)); onMount(async () => { + userColumns; /* silences lint check, variable not read */ + if (spreadsheetContainer) { resizeObserver = new ResizeObserver(recalcAll); resizeObserver.observe(spreadsheetContainer); @@ -430,6 +439,7 @@ $tableColumnSuggestions.enabled = false; } + $tableColumnSuggestions.force = undefined; $tableColumnSuggestions.context = null; $tableColumnSuggestions.thinking = false; @@ -739,7 +749,7 @@ tick().then(() => { selectedColumnId = columnData.key; selectedColumnName = columnData.key; - }) + }); }); } @@ -888,6 +898,8 @@ timeout: NOTIFICATION_AND_MOCK_DELAY }); + resetSuggestionsStore(true); + // show index notification! showIndexSuggestionsNotification(); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte index 31272972cf..f389a56c63 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte @@ -7,6 +7,12 @@ import { Button, InputTextarea } from '$lib/elements/forms'; import { Card, Layout, Selector, Typography } from '@appwrite.io/pink-svelte'; + const { + isModal = false + }: { + isModal?: boolean; + } = $props(); + onMount(() => { if (featureActive) { $tableColumnSuggestions.enabled = true; @@ -23,7 +29,9 @@ const subtitle = $derived.by(() => { return featureActive - ? 'Enable AI to suggest useful columns based on your table name' + ? isModal + ? 'Use AI to suggest useful columns' + : 'Enable AI to suggest useful columns based on your table name' : 'Sign up for Cloud to generate columns based on your table name'; }); @@ -42,7 +50,7 @@ - {#if featureActive} + {#if featureActive && !isModal}
({ export const showIndexesSuggestions = writable(false); +export const showColumnsSuggestionsModal = writable(false); + export const mockSuggestions: { total: number; columns: ColumnInput[] } = { total: 7, columns: [ 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 19aa513a5f..a341b5ac4d 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 @@ -65,7 +65,12 @@ import { Submit, trackEvent } from '$lib/actions/analytics'; import IndexesSuggestions from '../(suggestions)/indexes.svelte'; - import { showIndexesSuggestions, tableColumnSuggestions } from '../(suggestions)'; + import ColumnsSuggestions from '../(suggestions)/columns.svelte'; + import { + showColumnsSuggestionsModal, + showIndexesSuggestions, + tableColumnSuggestions + } from '../(suggestions)'; let editRow: EditRow; let editRelatedRow: EditRelatedRow; @@ -482,4 +487,6 @@ + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte index 45e3d7f3fe..e86e540099 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte @@ -38,7 +38,11 @@ import CreateRow from './rows/create.svelte'; import { onDestroy } from 'svelte'; import { isCloud } from '$lib/system'; - import { Empty as SuggestionsEmptySheet, tableColumnSuggestions } from '../(suggestions)'; + import { + Empty as SuggestionsEmptySheet, + tableColumnSuggestions, + showColumnsSuggestionsModal + } from '../(suggestions)'; import EmptySheetCards from './layout/emptySheetCards.svelte'; import IconAI from '../(suggestions)/icon/aiForButton.svelte'; @@ -201,7 +205,7 @@
- {#if hasColumns && hasValidColumns} + {#if hasColumns && hasValidColumns && $tableColumnSuggestions.force === false} {#if data.rows.total} @@ -250,7 +254,7 @@ {/if} {:else if isCloud && canShowSuggestionsSheet} - + {:else} {#snippet actions()} @@ -267,7 +271,7 @@ title="Suggest columns" subtitle="Use AI to generate columns" onClick={() => { - // todo: add a modal and show input, no toggle. + $showColumnsSuggestionsModal = true; }} /> import { page } from '$app/state'; - import { type Columns, type ColumnDirection } from './store'; - import { goto, invalidate } from '$app/navigation'; + import { invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; - import { Layout } from '@appwrite.io/pink-svelte'; + import { Alert, Layout, Link } from '@appwrite.io/pink-svelte'; import { InputSelect, InputText } from '$lib/elements/forms'; import { addNotification } from '$lib/stores/notifications'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; @@ -11,8 +10,10 @@ import type { Column } from '$lib/helpers/types'; import { preferences } from '$lib/stores/preferences'; import { onMount } from 'svelte'; - import { resolve } from '$app/paths'; - import { Input as SuggestionsInput, tableColumnSuggestions } from '../(suggestions)/index'; + + import { showColumnsSuggestionsModal } from '../(suggestions)/store'; + import IconAINotification from '../(suggestions)/icon/aiNotification.svelte'; + import { type Columns, type ColumnDirection, showCreateColumnSheet } from './store'; let { direction = null, @@ -52,16 +53,6 @@ columnOptions.find((option) => option.name === selectedOption).component ); - function initSuggestionsStore() { - if (!isSuggestionsFeatureEnabled) return; - - $tableColumnSuggestions.table = null; - $tableColumnSuggestions.enabled = false; - - $tableColumnSuggestions.context = null; - $tableColumnSuggestions.thinking = false; - } - function init() { key = null; $option = null; @@ -74,9 +65,6 @@ /* default to string */ selectedOption = 'String'; $option = columnOptions[0]; - - /* init suggestions */ - initSuggestionsStore(); } function insertColumnInOrder() { @@ -155,33 +143,6 @@ } export async function submit() { - if (isSuggestionsEnabled) { - const tableInUse = page.data.table; - // TODO: confirm what flow to use! - tableColumnSuggestions.update((store) => ({ - ...store, - thinking: true, - table: { - id: tableInUse.$id, - name: tableInUse.name - } - })); - - const { region, project, database, table } = page.params; - await goto( - resolve( - '/(console)/project-[region]-[project]/databases/database-[database]/table-[table]', - { - region, - project, - database, - table - } - ) - ); - return true; - } - try { await $option.create(databaseId, tableId, key, data); @@ -222,15 +183,23 @@ $option = columnOptions.find((option) => option.name === selectedOption); } }); - - const isSuggestionsEnabled = $derived( - isSuggestionsFeatureEnabled && $tableColumnSuggestions.enabled - ); {#if isSuggestionsFeatureEnabled} - +
+ + + + + + Need help? Let AI { + $showCreateColumnSheet.show = false; + $showColumnsSuggestionsModal = true; + }}>suggest columns based on your data + +
{/if} @@ -240,7 +209,7 @@ placeholder="Enter key" bind:value={key} autofocus - disabled={selectedOption === 'Relationship' || isSuggestionsEnabled} + disabled={selectedOption === 'Relationship'} required pattern="^[A-Za-z0-9][A-Za-z0-9._\-]*$" /> @@ -248,7 +217,6 @@ id="type" label="Type" bind:value={selectedOption} - disabled={isSuggestionsEnabled} options={columnOptions.map((attr) => { return { label: attr.name, @@ -260,9 +228,22 @@ {#if selectedOption} - ($option = null)} /> + ($option = null)} /> {/if}
+ + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte index a425ed44a1..665b016d9b 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte @@ -37,9 +37,9 @@ import { showCreateColumnSheet } from '../store'; import { isSmallViewport } from '$lib/stores/viewport'; import { page } from '$app/state'; - import { showIndexesSuggestions } from '../../(suggestions)'; + import { showIndexesSuggestions, showColumnsSuggestionsModal } from '../../(suggestions)'; import IconAI from '../../(suggestions)/icon/aiForButton.svelte'; - import EmptySheetCards from '$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/layout/emptySheetCards.svelte'; + import EmptySheetCards from '../layout/emptySheetCards.svelte'; let { data @@ -339,7 +339,7 @@ title="Suggest columns" subtitle="Use AI to generate columns" onClick={() => { - // TODO: add a modal and show input, no toggle. + $showColumnsSuggestionsModal = true; }} /> {/snippet}
From 1c8191f5c7e9a37dd203134b73c72bb6cd759992 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 19 Oct 2025 19:07:33 +0530 Subject: [PATCH 18/47] update: index suggestions empty state. --- .../table-[table]/indexes/+page.svelte | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte index 665b016d9b..8575711d67 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte @@ -290,7 +290,7 @@ {:else} - + {#snippet subtitle()} Need a hand? Learn more in the @@ -304,21 +304,21 @@ {#snippet actions()} { showIndexesSuggestions.update(() => true); }} /> { - showIndexesSuggestions.update(() => true); + showCreateIndex = true; }} /> {/snippet} From 292829d59c234977d95198a82188e08e7b304fa5 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 19 Oct 2025 19:08:36 +0530 Subject: [PATCH 19/47] fix: permissions check on empty state options --- .../database-[database]/table-[table]/indexes/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte index 8575711d67..b8752153a9 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte @@ -290,7 +290,7 @@ {:else} - + {#snippet subtitle()} Need a hand? Learn more in the From 09c6242bcc27eeb5247f37ce35c061d1fedd6998 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 19 Oct 2025 19:20:58 +0530 Subject: [PATCH 20/47] fix: view disappearing on columns gen modal > thinking sheet. update: actions on indexes empty state. --- .../database-[database]/(suggestions)/columns.svelte | 2 +- .../databases/database-[database]/(suggestions)/empty.svelte | 2 +- .../databases/database-[database]/(suggestions)/store.ts | 5 +++-- .../databases/database-[database]/table-[table]/+page.svelte | 2 +- .../database-[database]/table-[table]/indexes/+page.svelte | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte index 9cbea3a2aa..5673d8745e 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/columns.svelte @@ -22,9 +22,9 @@ $tableColumnSuggestions.table = null; $tableColumnSuggestions.context = null; + $tableColumnSuggestions.force = false; $tableColumnSuggestions.enabled = false; $tableColumnSuggestions.thinking = false; - $tableColumnSuggestions.force = undefined; } async function triggerColumnSuggestions() { diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 8e9fa2dfeb..9cc05b3048 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -436,10 +436,10 @@ // these are referenced in // `table-[table]/+page.svelte` $tableColumnSuggestions.table = null; + $tableColumnSuggestions.force = false; $tableColumnSuggestions.enabled = false; } - $tableColumnSuggestions.force = undefined; $tableColumnSuggestions.context = null; $tableColumnSuggestions.thinking = false; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts index 88b9143098..f05b5ca5dd 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts @@ -3,7 +3,7 @@ import { IndexType } from '@appwrite.io/console'; import { columnOptions } from '../table-[table]/columns/store'; export type TableColumnSuggestions = { - force?: boolean; + force: boolean; enabled: boolean; thinking: boolean; context?: string | undefined; @@ -44,7 +44,8 @@ export const tableColumnSuggestions = writable({ enabled: false, context: null, thinking: false, - table: null + table: null, + force: false, }); export const showIndexesSuggestions = writable(false); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte index e86e540099..1cce612e1a 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte @@ -205,7 +205,7 @@
- {#if hasColumns && hasValidColumns && $tableColumnSuggestions.force === false} + {#if hasColumns && hasValidColumns && !$tableColumnSuggestions.force} {#if data.rows.total} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte index b8752153a9..b8e9738bd6 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte @@ -324,7 +324,7 @@ {/if} {:else} - + {#snippet actions()} Date: Sun, 19 Oct 2025 19:28:25 +0530 Subject: [PATCH 21/47] address comments from coderabbit. --- .../database-[database]/(suggestions)/empty.svelte | 9 ++++++--- .../databases/database-[database]/(suggestions)/store.ts | 2 +- .../database-[database]/table-[table]/+page.svelte | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 9cc05b3048..9adb2b2d09 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -680,7 +680,7 @@ if (!columnId) return; let columnIndex = -1; - let columnSchema: SuggestedColumnSchema; + let columnSchema: SuggestedColumnSchema = null; for (let index = 0; index < customColumns.length; index++) { if (customColumns[index].key === columnId) { @@ -690,10 +690,13 @@ } } - if (columnIndex !== -1) { - customColumns.splice(columnIndex, 1); + if (columnIndex === -1 || !columnSchema) { + return; } + // remove the column + customColumns.splice(columnIndex, 1); + // store column with its index for undo columnBeingDeleted = { ...columnSchema, deletedIndex: columnIndex }; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts index f05b5ca5dd..a37d84a917 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/store.ts @@ -45,7 +45,7 @@ export const tableColumnSuggestions = writable({ context: null, thinking: false, table: null, - force: false, + force: false }); export const showIndexesSuggestions = writable(false); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte index 1cce612e1a..e440d2eb31 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte @@ -205,7 +205,7 @@
- {#if hasColumns && hasValidColumns && !$tableColumnSuggestions.force} + {#if hasColumns && hasValidColumns && $tableColumnSuggestions.force !== true} {#if data.rows.total} @@ -266,6 +266,7 @@ $showCreateColumnSheet.show = true; }} /> + Date: Sun, 19 Oct 2025 19:35:07 +0530 Subject: [PATCH 22/47] update: empty states on indexes for self-hosted. --- .../table-[table]/indexes/+page.svelte | 81 +++++++++++++------ 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte index b8e9738bd6..24467f354c 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte @@ -23,6 +23,7 @@ Typography } from '@appwrite.io/pink-svelte'; import { + IconBookOpen, IconDotsHorizontal, IconEye, IconPlus, @@ -40,6 +41,7 @@ import { showIndexesSuggestions, showColumnsSuggestionsModal } from '../../(suggestions)'; import IconAI from '../../(suggestions)/icon/aiForButton.svelte'; import EmptySheetCards from '../layout/emptySheetCards.svelte'; + import { isCloud } from '$lib/system'; let { data @@ -292,25 +294,29 @@ {:else} {#snippet subtitle()} - - Need a hand? Learn more in the - - docs. - - + {#if isCloud} + + Need a hand? Learn more in the + + docs. + + + {/if} {/snippet} {#snippet actions()} - { - showIndexesSuggestions.update(() => true); - }} /> + {#if isCloud} + { + showIndexesSuggestions.update(() => true); + }} /> + {/if} { showCreateIndex = true; }} /> + + {#if !isCloud} + + {/if} {/snippet} {/if} {:else} + {#snippet subtitle()} + {#if isCloud} + + Need a hand? Learn more in the + + docs. + + + {/if} + {/snippet} + {#snippet actions()} - { - $showColumnsSuggestionsModal = true; - }} /> + {#if isCloud} + { + $showColumnsSuggestionsModal = true; + }} /> + {:else} + + {/if} {/snippet} {/if} From b2fb9dd57246d11a31090fd0b78a77a3f57f9d38 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 19 Oct 2025 19:41:01 +0530 Subject: [PATCH 23/47] update: empty states on rows for self-hosted. --- .../table-[table]/+page.svelte | 47 +++++++++++++------ .../table-[table]/indexes/+page.svelte | 4 +- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte index e440d2eb31..63089d7f33 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte @@ -6,7 +6,7 @@ import { Container } from '$lib/layout'; import { preferences } from '$lib/stores/preferences'; import { canWriteTables, canWriteRows } from '$lib/stores/roles'; - import { Icon, Layout, Divider, Tooltip } from '@appwrite.io/pink-svelte'; + import { Icon, Layout, Divider, Tooltip, Typography, Link } from '@appwrite.io/pink-svelte'; import type { PageData } from './$types'; import { table, @@ -257,6 +257,20 @@ {:else} + {#snippet subtitle()} + {#if !isCloud} + + + Need a hand? Learn more in the + + docs. + + + {/if} + {/snippet} + {#snippet actions()} - - { - $showColumnsSuggestionsModal = true; - }} /> + {#if isCloud} + + { + $showColumnsSuggestionsModal = true; + }} /> + {/if} - + {#if isCloud} + + + {/if} {/snippet} {/if} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte index 24467f354c..11a89554e8 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/indexes/+page.svelte @@ -331,7 +331,7 @@ {/if} {/snippet} @@ -373,7 +373,7 @@ {/if} {/snippet} From cc795fa561d9c369fafd92a1863d56179573d3a6 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 19 Oct 2025 19:46:11 +0530 Subject: [PATCH 24/47] update: hide ai suggestion inline alert if not cloud, for now. --- .../database-[database]/table-[table]/createColumn.svelte | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte index 1285e35857..97f06e128d 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte @@ -14,6 +14,7 @@ import { showColumnsSuggestionsModal } from '../(suggestions)/store'; import IconAINotification from '../(suggestions)/icon/aiNotification.svelte'; import { type Columns, type ColumnDirection, showCreateColumnSheet } from './store'; + import { isCloud } from '$lib/system'; let { direction = null, @@ -38,9 +39,6 @@ const tableId = page.params.table; const databaseId = page.params.database; - // flow isn't complete yet! - const isSuggestionsFeatureEnabled = true; - let key: string = $state(column?.key ?? null); let data: Partial = $state({ required: column?.required ?? false, @@ -186,7 +184,7 @@ - {#if isSuggestionsFeatureEnabled} + {#if isCloud}
From 5380a6aece3c8cd33b35114977ec26751f2ee454 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 19 Oct 2025 19:47:22 +0530 Subject: [PATCH 25/47] fix: column id for deletion. --- .../databases/database-[database]/(suggestions)/empty.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index 9adb2b2d09..e02979d30f 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -1309,7 +1309,7 @@ if (isUndoDeleteMode) { undoDelete(); } else { - deleteColumn(selectedColumnName); + deleteColumn(selectedColumnId); } }}> {#if isUndoDeleteMode} From d8cd72ca0b8c0f969b6d74027613fda3eb99ec51 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 20 Oct 2025 12:31:06 +0530 Subject: [PATCH 26/47] ci: empty commit From 5eaeccf7d0e78fd0bbaf87c4746fdef09d9c497f Mon Sep 17 00:00:00 2001 From: Darshan Date: Tue, 21 Oct 2025 16:04:08 +0530 Subject: [PATCH 27/47] address design review comments. --- .../(suggestions)/empty.svelte | 128 +++++++++++++++--- .../(suggestions)/input.svelte | 6 +- .../table-[table]/+page.svelte | 20 +-- .../table-[table]/createColumn.svelte | 9 +- .../table-[table]/indexes/+page.svelte | 24 ++-- .../table-[table]/layout/emptySheet.svelte | 27 ++-- 6 files changed, 163 insertions(+), 51 deletions(-) diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte index e02979d30f..6072015d1e 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/empty.svelte @@ -1012,6 +1012,38 @@ }); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- + - {#if isUndoDeleteMode} - was deleted. You can undo this action. - {:else} - column selected - {/if} - + + {#if isUndoDeleteMode} + was deleted. You can undo this action. + {:else} + column selected + {/if} + + @@ -1299,6 +1337,9 @@ on:click={() => (selectedColumnId = null)}> Cancel + + + {/if} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte index f389a56c63..70dec29632 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(suggestions)/input.svelte @@ -70,7 +70,7 @@ {#if $tableColumnSuggestions.enabled && featureActive} -
+
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte index 63089d7f33..29446deae5 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte @@ -245,7 +245,7 @@ { $randomDataModalState.show = true; @@ -272,14 +272,6 @@ {/snippet} {#snippet actions()} - { - $showCreateColumnSheet.show = true; - }} /> - {#if isCloud} {/if} + { + $showCreateColumnSheet.show = true; + }} /> + { $randomDataModalState.show = true; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte index 97f06e128d..039b0a854d 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/createColumn.svelte @@ -39,6 +39,8 @@ const tableId = page.params.table; const databaseId = page.params.database; + let showSuggestionsAlert = $state(true); + let key: string = $state(column?.key ?? null); let data: Partial = $state({ required: column?.required ?? false, @@ -184,9 +186,9 @@ - {#if isCloud} + {#if isCloud && showSuggestionsAlert}
- + (showSuggestionsAlert = false)}> @@ -233,7 +235,10 @@