Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "^2.0.0-RC.1",
"@appwrite.io/pink-legacy": "^1.0.3",
"@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@ee1b778",
"@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@efb9310",
"@popperjs/core": "^2.11.8",
"@sentry/sveltekit": "^8.38.0",
"@stripe/stripe-js": "^3.5.0",
Expand Down
35 changes: 25 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/lib/components/columnSelector.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
} = $props();

let maxHeight = $state('none');
let containerRef;
let containerRef: HTMLDivElement = $state();

const calcMaxHeight = () => {
if (containerRef) {
Expand Down Expand Up @@ -67,7 +67,7 @@
calcMaxHeight();
});

let selectedColumnsNumber = $derived(
const selectedColumnsNumber = $derived(
$columns.reduce((acc, column) => {
if (column.hide === true) return acc;

Expand Down
2 changes: 1 addition & 1 deletion src/lib/stores/preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ function createPreferences() {
);
},
getCustomCollectionColumns: (collectionId: string): Preferences['columns'] => {
return preferences?.collections?.[collectionId] ?? [];
return preferences?.collections?.[collectionId] ?? null;
},
setLimit: (limit: Preferences['limit']) =>
updateAndSync((n) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import CreateAttribute from './createAttribute.svelte';
import { collection, columns, isCsvImportInProgress } from './store';
import Table from './table.svelte';
import { writable } from 'svelte/store';
import FilePicker from '$lib/components/filePicker.svelte';
import { page } from '$app/state';
import { sdk } from '$lib/stores/sdk';
Expand All @@ -32,28 +31,22 @@
let showCreateAttribute = false;
let selectedAttribute: Option['name'] = null;

const filterColumns = writable<Column[]>([]);

$: selected = preferences.getCustomCollectionColumns(page.params.collection);
$: columns.set(
$collection.attributes.map((attribute) => ({

$: columns.set([
{ id: '$id', width: 200, title: 'Document ID', type: 'string' },
...$collection.attributes.map<Column>((attribute) => ({
id: attribute.key,
title: attribute.key,
type: attribute.type as ColumnType,
show: selected?.includes(attribute.key) ?? true,
hide: !(selected?.includes(attribute.key) ?? true),
array: attribute?.array,
width: { min: 168 },
format: 'format' in attribute && attribute?.format === 'enum' ? attribute.format : null,
elements: 'elements' in attribute ? attribute.elements : null
}))
);
$: filterColumns.set([
...$columns,
...['$id', '$createdAt', '$updatedAt'].map((id) => ({
id,
title: id,
show: true,
type: (id === '$id' ? 'string' : 'datetime') as ColumnType
}))
})),
{ id: '$created', width: 200, title: 'Created', type: 'datetime' },
{ id: '$updated', width: 200, title: 'Updated', type: 'datetime' }
]);

$: hasAttributes = !!$collection.attributes.length;
Expand Down Expand Up @@ -99,7 +92,7 @@
disabled={!(hasAttributes && hasValidAttributes)}
analyticsSource="database_documents" />
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
<ViewSelector view={data.view} {columns} hideView />
<ViewSelector view={data.view} {columns} hideView isCustomCollection />
{#if flags.showCsvImport(data)}
<Button
secondary
Expand Down Expand Up @@ -133,7 +126,7 @@

{#if hasAttributes && hasValidAttributes}
{#if data.documents.total}
<Table {data} />
<Table {data} {columns} />

<PaginationWithLimit
name="Documents"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@
import { preferences } from '$lib/stores/preferences';
import { sdk } from '$lib/stores/sdk';
import type { Models } from '@appwrite.io/console';
import { afterUpdate, onMount } from 'svelte';
import { onMount } from 'svelte';
import type { PageData } from './$types';
import {
isRelationship,
isRelationshipToMany,
isString
} from './document-[document]/attributes/store';
import RelationshipsModal from './relationshipsModal.svelte';
import { attributes, collection, columns } from './store';
import type { ColumnType } from '$lib/helpers/types';
import { attributes, collection } from './store';
import {
Tooltip,
Table,
Expand All @@ -33,8 +32,11 @@
import { toLocaleDateTime } from '$lib/helpers/date';
import DualTimeView from '$lib/components/dualTimeView.svelte';
import { flags } from '$lib/flags';
import type { Writable } from 'svelte/store';
import type { Column } from '$lib/helpers/types';

export let data: PageData;
export let columns: Writable<Column[]>;

const databaseId = page.params.database;
const collectionId = page.params.collection;
Expand All @@ -45,23 +47,8 @@

onMount(async () => {
displayNames = preferences.getDisplayNames();
updateMaxWidth();
});

afterUpdate(() => updateMaxWidth());

function updateMaxWidth() {
const tableCells = Array.from(document.querySelectorAll('.less-width-truncated'));

const visibleColumnsCount = $columns.filter((col) => !col.hide).length;
const newMaxWidth = Math.max(50 - (visibleColumnsCount - 1) * 5, 25);

tableCells.forEach((cell) => {
const cellItem = cell as HTMLElement;
cellItem.style.maxWidth = `${newMaxWidth}vw`;
});
}

function formatArray(array: unknown[]) {
if (array.length === 0) return '[ ]';

Expand Down Expand Up @@ -100,24 +87,6 @@
};
}

$: selected = preferences.getCustomCollectionColumns(page.params.collection);

$: {
columns.set(
$collection.attributes.map((attribute) => ({
id: attribute.key,
title: attribute.key,
type: attribute.type as ColumnType,
show: selected?.includes(attribute.key) ?? true,
array: attribute?.array,
width: { min: 168 },
format:
'format' in attribute && attribute?.format === 'enum' ? attribute.format : null,
elements: 'elements' in attribute ? attribute.elements : null
}))
);
}

let selectedRows: string[] = [];
let showDelete = false;

Expand Down Expand Up @@ -173,41 +142,42 @@
const showEncrypt = flags.showAttributeEncrypt(data);
</script>

<Table.Root
let:root
allowSelection
bind:selectedRows
columns={[
{ id: '$id', width: 200 },
...$columns,
{ id: '$created', width: 200 },
{ id: '$updated', width: 200 }
]}>
<svelte:fragment slot="header" let:root>
<Table.Header.Cell column="$id" {root}>Document ID</Table.Header.Cell>
{#each $columns as column}
<Table.Header.Cell column={column.id} {root}>{column.title}</Table.Header.Cell>
<Table.VirtualRoot let:root let:virtualizer allowSelection bind:selectedRows columns={$columns}>
<svelte:fragment slot="header" let:root let:virtualizer>
{#each virtualizer.getVirtualItems() as item (item.index)}
{@const column = $columns[item.index]}
<Table.VirtualCell column={column.id} {root} virtualItem={item}>
{column.title}
</Table.VirtualCell>
{/each}
<Table.Header.Cell column="$created" {root}>Created</Table.Header.Cell>
<Table.Header.Cell column="$updated" {root}>Updated</Table.Header.Cell>
</svelte:fragment>
{#each data.documents.documents as document (document.$id)}
<Table.Row.Link
{root}
id={document.$id}
href={`${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}/collection-${$collection.$id}/document-${document.$id}`}>
<Table.Cell column="$id" {root}>
{#key document.$id}
<Id value={document.$id}>
{document.$id}
</Id>
{/key}
</Table.Cell>

{#each $columns as { id } (id)}
{@const attr = $attributes.find((n) => n.key === id)}
{#if attr}
<Table.Cell column={id} {root}>
{#each virtualizer.getVirtualItems() as item (item.index)}
{@const column = $columns[item.index]}
{#if column.id === '$id'}
<Table.VirtualCell column="$id" {root} virtualItem={item}>
{#key document.$id}
<Id value={document.$id}>
{document.$id}
</Id>
{/key}
</Table.VirtualCell>
{:else if column.id === '$created'}
<Table.VirtualCell column="$created" {root} virtualItem={item}>
<DualTimeView time={document.$createdAt} />
</Table.VirtualCell>
{:else if column.id === '$updated'}
<Table.VirtualCell column="$updated" {root} virtualItem={item}>
<DualTimeView time={document.$updatedAt} />
</Table.VirtualCell>
{:else}
{@const id = column.id}
{@const attr = $attributes.find((n) => n.key === id)}
Copy link
Preview

Copilot AI Jun 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling .find on $attributes for every cell renders in O(n) per cell. Precompute a lookup map (e.g., {[key]: attribute}) before rendering to achieve constant-time attribute access.

Suggested change
{@const attr = $attributes.find((n) => n.key === id)}
{@const attr = attributesMap[id]}

Copilot uses AI. Check for mistakes.

<Table.VirtualCell column={id} {root} virtualItem={item}>
{#if isRelationship(attr)}
{@const args = displayNames?.[attr.relatedCollection] ?? ['$id']}
{#if !isRelationshipToMany(attr)}
Expand Down Expand Up @@ -253,23 +223,20 @@
</Button.Button>
{/if}
{:else}
{@const datetime = document[id]}
{@const formatted = formatColumn(document[id])}
{@const isDatetimeAttribute = attr.type === 'datetime'}
{@const isEncryptedAttribute = isString(attr) && attr.encrypt}
{#if isDatetimeAttribute}
<DualTimeView time={datetime}>
<DualTimeView time={document[id]}>
<span slot="title">Timestamp</span>
{toLocaleDateTime(datetime, true)}
{toLocaleDateTime(document[id], true)}
</DualTimeView>
{:else if isEncryptedAttribute && showEncrypt}
<button on:click={(e) => e.preventDefault()}>
<InteractiveText
copy={false}
variant="secret"
isVisible={false}
text={formatted.value} />
</button>
<InteractiveText
copy={false}
variant="secret"
isVisible={false}
text={formatted.value} />
{:else if formatted.truncated}
<Tooltip placement="bottom" disabled={!formatted.truncated}>
<Typography.Text truncate>{formatted.value}</Typography.Text>
Expand All @@ -287,18 +254,12 @@
<Typography.Text truncate>{formatted.value}</Typography.Text>
{/if}
{/if}
</Table.Cell>
</Table.VirtualCell>
{/if}
{/each}
<Table.Cell column="$created" {root}>
<DualTimeView time={document.$createdAt} />
</Table.Cell>
<Table.Cell column="$updated" {root}>
<DualTimeView time={document.$updatedAt} />
</Table.Cell>
</Table.Row.Link>
{/each}
</Table.Root>
</Table.VirtualRoot>

<RelationshipsModal bind:show={showRelationships} {selectedRelationship} data={relationshipData} />

Expand Down
Loading