feat: open sheet on old document-* and row-* urls.

This commit is contained in:
Darshan
2025-08-27 15:34:46 +05:30
parent cfc78804c5
commit ac165ea02f
5 changed files with 97 additions and 19 deletions
@@ -2,32 +2,57 @@ import { base } from '$app/paths';
import type { PageLoad } from './$types';
import { redirect } from '@sveltejs/kit';
import { AppwriteException } from '@appwrite.io/console';
import { databaseRowSheetOptions } from '../table-[table]/store';
const LEGACY_ROUTE_MAPPINGS = [
const ROUTE_MAPPINGS: {
pattern: RegExp;
replacement?: string;
sheet?: 'row' | 'column';
}[] = [
{ pattern: /^collection-([^/]+)/, replacement: 'table-$1' },
// document detail page redirect to their parent table
{ pattern: /^document-([^/]+)/, replacement: 'table-$1' },
{ pattern: /^document-([^/]+)/, sheet: 'row' },
// attribute detail redirect to table columns
{ pattern: /^attribute-([^/]+)/, replacement: 'table-$1/columns' },
// attributes list page redirect to table columns
{ pattern: /^attributes$/, replacement: 'columns' }
{ pattern: /^attributes$/, replacement: 'columns' },
// New format routes,
{ pattern: /^row-([^/]+)/, sheet: 'row' }
] as const;
function isLegacyRoute(segments: string[]): boolean {
return segments.some((segment) =>
LEGACY_ROUTE_MAPPINGS.some((mapping) => mapping.pattern.test(segment))
ROUTE_MAPPINGS.some((mapping) => mapping.pattern.test(segment))
);
}
function rewriteLegacySegments(segments: string[]): string[] {
return segments.map((segment) => {
for (const mapping of LEGACY_ROUTE_MAPPINGS) {
if (mapping.pattern.test(segment)) {
return segment.replace(mapping.pattern, mapping.replacement);
return segments
.map((segment) => {
for (const mapping of ROUTE_MAPPINGS) {
if (mapping.pattern.test(segment)) {
if (mapping.sheet && mapping.sheet === 'row') {
const match = segment.match(mapping.pattern);
if (match && match[1]) {
databaseRowSheetOptions.update((options) => ({
...options,
rowId: match[1],
title: 'Update row',
mode: 'redirect'
}));
}
}
return !mapping.replacement
? null
: segment.replace(mapping.pattern, mapping.replacement);
}
}
}
return segment;
});
return segment;
})
.filter(Boolean);
}
export const load: PageLoad = async ({ params, url }) => {
@@ -383,7 +383,10 @@
disabled: editRow?.isDisabled(),
onClick: async () => await editRow?.update()
}}>
<EditRow bind:row={$databaseRowSheetOptions.row} bind:this={editRow} />
<EditRow
bind:this={editRow}
bind:row={$databaseRowSheetOptions.row}
bind:rowId={$databaseRowSheetOptions.rowId} />
</SideSheet>
<SideSheet
@@ -10,19 +10,23 @@
import { invalidate } from '$app/navigation';
import { table, type Columns, PROHIBITED_ROW_KEYS } from '../store';
import ColumnItem from './columns/columnItem.svelte';
import { isRelationship, isRelationshipToMany } from './store';
import { Layout } from '@appwrite.io/pink-svelte';
import { buildWildcardColumnsQuery, isRelationship, isRelationshipToMany } from './store';
import { Layout, Skeleton } from '@appwrite.io/pink-svelte';
import { deepClone } from '$lib/helpers/object';
const tableId = page.params.table;
const databaseId = page.params.database;
let {
row = $bindable()
row = $bindable(),
rowId = $bindable(null)
}: {
row: Models.Row;
row?: Models.Row | null;
rowId?: string | null;
} = $props();
let loading = $state(false);
let work = $state<Writable<Models.Row> | null>(null);
let columnFormWrapper = $state<HTMLElement | null>(null);
@@ -39,10 +43,42 @@
return writable(deepClone(result as Models.Row));
}
async function loadRowFromId() {
if (!rowId) return;
loading = true;
try {
row = await sdk.forProject(page.params.region, page.params.project).tablesDB.getRow({
databaseId,
tableId,
rowId,
queries: buildWildcardColumnsQuery($table)
});
} catch (error) {
addNotification({
message: `Failed to load row: ${error.message}`,
type: 'error'
});
row = null;
} finally {
rowId = null;
loading = false;
}
}
$effect(() => {
if (!row && rowId) {
loadRowFromId();
}
});
$effect(() => {
if (row) {
work = initWork();
focusFirstInput();
} else {
work = null;
}
});
@@ -81,6 +117,8 @@
}
export async function update() {
if (!row || !work) return;
try {
await sdk.forProject(page.params.region, page.params.project).tablesDB.updateRow({
databaseId,
@@ -106,7 +144,7 @@
}
export function isDisabled(): boolean {
if (!work || !$table?.columns?.length) return true;
if (!work || !row || !$table?.columns?.length) return true;
return $table.columns.every((column) => compareColumns(column, $work, row));
}
@@ -120,7 +158,11 @@
}
</script>
{#if $table.columns?.length && work}
{#if loading}
<div style:margin-block="" style:margin-inline-end="2.25rem">
<Skeleton variant="line" height={40} width="auto" />
</div>
{:else if $table.columns?.length && work}
<div bind:this={columnFormWrapper}>
<Layout.Stack direction="column" gap="l">
{#each $table.columns as column}
@@ -132,6 +132,11 @@
paginatedRows.clear();
paginatedRows.setPage(1, data.rows.rows);
}
// rowId exists, we have someone from old url format!
if ($databaseRowSheetOptions && $databaseRowSheetOptions.rowId) {
setTimeout(() => ($databaseRowSheetOptions.show = true), 250);
}
});
onDestroy(() => ($showCreateColumnSheet.show = false));
@@ -57,11 +57,13 @@ export const databaseColumnSheetOptions = writable<DatabaseSheetOptions>({
export const databaseRowSheetOptions = writable<
DatabaseSheetOptions & {
row: Models.Row;
rowId?: string;
}
>({
title: null,
show: false,
row: null
row: null,
rowId: null // for loading from a given id
});
export const databaseRelatedRowSheetOptions = writable<
@@ -177,6 +179,7 @@ export const paginatedRows = createSparsePagedDataStore<Models.DefaultRow>(SPREA
export const PROHIBITED_ROW_KEYS = [
'$id',
'$sequence',
'$collection',
'$tableId',
'$databaseId',