vectorsdb collection page and empty state bugs

This commit is contained in:
Prem Palanisamy
2026-03-20 08:32:53 +00:00
parent 218be1405b
commit 5d0e4ffddd
10 changed files with 58 additions and 29 deletions
@@ -2,6 +2,7 @@ import { sdk } from '$lib/stores/sdk';
import type { Page } from '@sveltejs/kit';
import type { TerminologyResult } from './types';
import {
type CollectionDatabaseType,
type DatabaseType,
type Entity,
type EntityList,
@@ -111,6 +112,22 @@ export type DatabaseSdkResult = {
}) => Promise<{}>;
};
/**
* Returns the raw DocumentsDB or VectorsDB SDK service for a given database type.
* Use in load functions (.ts) where Svelte runes aren't available.
*/
export function getCollectionService(region: string, project: string, type: CollectionDatabaseType) {
const projectSdk = sdk.forProject(region, project);
switch (type) {
case 'documentsdb':
return projectSdk.documentsDB;
case 'vectorsdb':
return projectSdk.vectorsDB;
default:
throw new Error(`Unsupported collection database type: ${type}`);
}
}
export function useDatabaseSdk(
regionOrPage: string | Page,
projectOrTerminology: string | TerminologyResult,
@@ -10,6 +10,9 @@ type ImplementedDBTypes = Omit<BaseTerminology, 'legacy'>;
/* manual type for the time being because vectorsdb is pending */
export type DatabaseType = 'legacy' | 'tablesdb' | 'documentsdb' | 'vectorsdb';
export type CollectionDatabaseType = Extract<DatabaseType, 'documentsdb' | 'vectorsdb'>;
export const DEFAULT_VECTOR_DIMENSION = 768;
export type RecordType = ImplementedDBTypes[keyof ImplementedDBTypes]['record'];
@@ -63,9 +66,9 @@ export const baseTerminology = {
record: 'document'
},
vectorsdb: {
entity: 'table',
field: 'column',
record: 'row'
entity: 'collection',
field: 'attribute',
record: 'document'
}
} as const;
@@ -4,14 +4,14 @@
import { Modal, CustomId } from '$lib/components';
import { subNavigation } from '$lib/stores/database';
import { ID } from '@appwrite.io/console';
import { Button, InputText } from '$lib/elements/forms';
import { Button, InputNumber, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import {
Input as SuggestionsInput,
entityColumnSuggestions
} from '$database/(suggestions)/index';
import { getTerminologies } from '../helpers';
import { getTerminologies, DEFAULT_VECTOR_DIMENSION } from '$database/(entity)';
import { resetSampleFieldsConfig } from '$database/store';
let {
@@ -21,7 +21,7 @@
}: {
show: boolean;
useSuggestions?: boolean;
onCreateEntity: (id: string, name: string) => Promise<void>;
onCreateEntity: (id: string, name: string, dimension?: number) => Promise<void>;
} = $props();
const { analytics, terminology } = getTerminologies();
@@ -29,12 +29,14 @@
const lower = terminology.entity.lower.singular;
const title = terminology.entity.title.singular;
const analyticsCreateSubmit = analytics.submit.entity('Create');
const isVectorsDb = terminology.type === 'vectorsdb';
// example - `table-[table]`, `collection-[collection]`
const isOnEntitiesPage = $derived(page.route?.id.endsWith(`${lower}-[${lower}]`));
let name = $state('');
let id = $state(null);
let dimension = $state(DEFAULT_VECTOR_DIMENSION);
let error = $state(null);
let creatingEntity = $state(false);
@@ -64,7 +66,7 @@
enableThinkingModeForSuggestions(finalId, name);
// create entity.
await onCreateEntity(finalId, name);
await onCreateEntity(finalId, name, isVectorsDb ? dimension : undefined);
// cleanup
updateAndCleanup();
@@ -121,6 +123,15 @@
<CustomId show bind:id required={false} autofocus={false} name={title} syncFrom={name} />
{#if isVectorsDb}
<InputNumber
id="dimension"
label="Vector dimension"
bind:value={dimension}
min={1}
required />
{/if}
{#if useSuggestions}
<SuggestionsInput showSampleCountPicker={!terminology.schema} />
{/if}
@@ -292,7 +292,7 @@
const spreadsheetColumns = $derived.by(() => {
return isRecordMode
? type !== 'documentsdb'
? type === 'tablesdb' || type === 'legacy'
? getRowColumns()
: getDocumentsDbColumns()
: getIndexesColumns();
@@ -382,7 +382,7 @@
{#snippet noSqlEditor()}
{#if showNoSqlEditor}
{#if type === 'documentsdb' && mode === 'records'}
{#if (type === 'documentsdb' || type === 'vectorsdb') && mode === 'records'}
<NoSqlEditor loading />
{/if}
{/if}
@@ -411,7 +411,7 @@
</Layout.Stack>
{#if showActions && actions}
{@const isOnlyIndexes = mode === 'indexes' && type === 'documentsdb'}
{@const isOnlyIndexes = mode === 'indexes' && (type === 'documentsdb' || type === 'vectorsdb')}
{@const inline = mode === 'records-filtered' || isOnlyIndexes}
<div class="controlled-width" class:single-mode={isOnlyIndexes}>
<Layout.Stack
@@ -504,7 +504,8 @@
}
}
&[data-mode='records'][data-type='documentsdb'] {
&[data-mode='records'][data-type='documentsdb'],
&[data-mode='records'][data-type='vectorsdb'] {
position: unset;
// disable animation when not loading!
&[data-loading='false'] :global(.skeleton) {
@@ -49,6 +49,7 @@
import { Button } from '$lib/elements/forms';
import { copy } from '$lib/helpers/copy';
import { isSmallViewport } from '$lib/stores/viewport';
import { isMac } from '$lib/helpers/platform';
import { makeErrorMessage } from './helpers/errorMessages';
import { customTheme, customSyntaxHighlighting } from './helpers/theme';
@@ -1512,7 +1513,7 @@
gap="xxxs"
alignItems="center"
style="height: fit-content">
<Badge content="⌘" variant="secondary" size="xs" />
<Badge content={isMac() ? '⌘' : 'Ctrl'} variant="secondary" size="xs" />
<Badge content="G" variant="secondary" size="xs" />
</Layout.Stack>
<Typography.Caption variant="400" color="--fgcolor-neutral-secondary">
@@ -53,6 +53,7 @@
RecordActivity,
CreateIndex,
useDatabaseSdk,
DEFAULT_VECTOR_DIMENSION,
type Field,
type Index
} from '$database/(entity)';
@@ -277,7 +278,7 @@
const dbType = data.database?.type;
const isVectorsDb = dbType === 'vectorsdb';
const dimension = collection?.dimension ?? 768;
const dimension = collection?.dimension ?? DEFAULT_VECTOR_DIMENSION;
// For vectorsdb, wrap fields in metadata and add empty embeddings
const documents = isVectorsDb
@@ -260,7 +260,7 @@
{/snippet}
</EmptySheet>
{:else}
<EmptySheet mode="records" type="documentsdb" showActions={$canWriteRows}>
<EmptySheet mode="records" type={data.database.type} showActions={$canWriteRows}>
{#snippet actions()}
<EmptySheetCards
icon={IconViewBoards}
@@ -1,12 +1,12 @@
import { Dependencies, SPREADSHEET_PAGE_LIMIT } from '$lib/constants';
import { getLimit, getPage, getQuery, getView, pageToOffset, View } from '$lib/helpers/load';
import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
import { queries, queryParamToMap } from '$lib/components/filters';
import { buildGridQueries, extractSortFromQueries } from '$database/store';
import { getCollectionService } from '$database/(entity)';
export const load: PageLoad = async ({ params, depends, url, route, parent }) => {
const { collection } = await parent();
const { collection, database } = await parent();
depends(Dependencies.DOCUMENTS);
const page = getPage(url);
@@ -20,6 +20,7 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) =>
queries.set(parsedQueries);
const currentSort = extractSortFromQueries(parsedQueries);
const collectionSdk = getCollectionService(params.region, params.project, database.type);
return {
offset,
@@ -28,7 +29,7 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) =>
query,
currentSort,
parsedQueries,
documents: await sdk.forProject(params.region, params.project).documentsDB.listDocuments({
documents: await collectionSdk.listDocuments({
databaseId: params.database,
collectionId: params.collection,
queries: buildGridQueries(limit, offset, parsedQueries, collection)
@@ -1,8 +1,8 @@
import { sdk } from '$lib/stores/sdk';
import type { PageLoad } from './$types';
import { PAGE_LIMIT } from '$lib/constants';
import { Query } from '@appwrite.io/console';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { getCollectionService } from '$database/(entity)';
export const load: PageLoad = async ({ params, url, route, parent }) => {
const { database } = await parent();
@@ -10,15 +10,12 @@ export const load: PageLoad = async ({ params, url, route, parent }) => {
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
const projectSdk = sdk.forProject(params.region, params.project);
const logsFn = database.type === 'vectorsdb'
? projectSdk.vectorsDB.listCollectionLogs.bind(projectSdk.vectorsDB)
: projectSdk.documentsDB.listCollectionLogs.bind(projectSdk.documentsDB);
const collectionSdk = getCollectionService(params.region, params.project, database.type);
return {
offset,
limit,
logs: await logsFn({
logs: await collectionSdk.listCollectionLogs({
databaseId: params.database,
collectionId: params.collection,
queries: [Query.limit(limit), Query.offset(offset)]
@@ -1,7 +1,7 @@
import { isValueOfStringEnum } from '$lib/helpers/types';
import { sdk } from '$lib/stores/sdk';
import { UsageRange } from '@appwrite.io/console';
import type { PageLoad } from './$types';
import { getCollectionService } from '$database/(entity)';
export const load: PageLoad = async ({ params, parent }) => {
const { database } = await parent();
@@ -9,13 +9,10 @@ export const load: PageLoad = async ({ params, parent }) => {
? params.period
: UsageRange.ThirtyDays;
const projectSdk = sdk.forProject(params.region, params.project);
const usageFn = database.type === 'vectorsdb'
? projectSdk.vectorsDB.getCollectionUsage.bind(projectSdk.vectorsDB)
: projectSdk.documentsDB.getCollectionUsage.bind(projectSdk.documentsDB);
const collectionSdk = getCollectionService(params.region, params.project, database.type);
return {
...(await usageFn({
...(await collectionSdk.getCollectionUsage({
databaseId: params.database,
collectionId: params.collection,
range: period