fix: remaining routes

This commit is contained in:
Torsten Dittmann
2025-09-15 21:46:38 +04:00
parent 4cb12f3772
commit 6f8031b2d2
71 changed files with 4660 additions and 5285 deletions
+52
View File
@@ -0,0 +1,52 @@
# Repository Guidelines
## Project Structure & Module Organization
- `src/`: SvelteKit app source.
- `src/lib/`: reusable components, elements, actions, helpers, stores, charts, images.
- `src/routes/`: route groups and pages (e.g., `+layout.svelte`, `+page.ts`).
- `src/themes/`, `hooks.*.ts`, `service-worker.ts`: app-wide setup.
- `static/`: public assets served as-is.
- `build/`: compiled output (local builds).
- `e2e/`: Playwright tests (`helpers/`, `journeys/`, `steps/`).
- Tooling: `eslint.config.js`, `.prettierrc`, `playwright.config.ts`, `vitest-setup-client.ts`.
## Build, Test, and Development Commands
- `pnpm dev`: start Vite dev server.
- `pnpm build`: production build via `build.js`.
- `pnpm preview`: preview the production build.
- `pnpm check`: Svelte/TS diagnostics.
- `pnpm format` / `pnpm lint`: format with Prettier, then lint with ESLint.
- `pnpm test` | `pnpm test:watch` | `pnpm test:ui`: run Vitest (unit/component tests).
- `pnpm e2e` | `pnpm e2e:ui`: run Playwright tests; config auto-builds and serves.
Requires Node >= 20 and pnpm (see `packageManager`).
## Coding Style & Naming Conventions
- Language: TypeScript + Svelte.
- Prettier: 4space indentation, single quotes, width 100, bracketSameLine.
- Svelte files: PascalCase components in `src/lib`, route files follow SvelteKit (`+page.svelte`, `+layout.ts`).
- Variables/functions: `camelCase`; constants: `SCREAMING_SNAKE_CASE`; types/interfaces: `PascalCase`.
- Keep logic in `$lib` and thin route loaders/actions.
## Testing Guidelines
- Unit/component: Vitest + Testing Library.
- Place near source or under `src/`; name `*.test.ts`/`*.test.svelte`.
- Run with `pnpm test`.
- Endtoend: Playwright under `e2e/`.
- Start with `pnpm e2e` (uses `playwright.config.ts` to build/preview on port 4173).
## Commit & Pull Request Guidelines
- Branch names: `TYPE-ISSUEID-short-description` (e.g., `feat-1234-add-billing-chart`).
- Commits: imperative, concise, reference issues when relevant.
- PRs: clear description, linked issues, screenshots/GIFs for UI changes, test coverage notes, and checklist of affected areas.
- Keep PRs focused; include `pnpm format`, `pnpm lint`, `pnpm check`, and `pnpm test` clean runs before requesting review.
## Security & Configuration Tips
- Do not commit secrets; use `.env` based on `.env.example`.
- Sentry/Stripe and other public keys are configured via env vars; prefer `PUBLIC_` prefix for clientexposed values.
- Use `compose.yml`/`Dockerfile` for containerized workflows when needed.
+3751 -4964
View File
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,8 @@
import { canWriteProjects } from '$lib/stores/roles';
import { Typography } from '@appwrite.io/pink-svelte';
const path = `${base}/project-${page.params.region}-${page.params.project}/auth`;
export let path = `${base}/project-${page.params.region}-${page.params.project}/auth`;
const tabs = [
{
href: path,
@@ -6,7 +6,8 @@
import { Cover, CoverTitle } from '$lib/layout';
import { team } from './store';
const path = `${base}/project-${page.params.region}-${page.params.project}/auth/teams/team-${page.params.team}`;
export let path = `${base}/project-${page.params.region}-${page.params.project}/auth/teams/team-${page.params.team}`;
export let back = `${base}/project-${page.params.region}-${page.params.project}/auth/teams`;
const tabs = [
{
href: path,
@@ -30,8 +31,7 @@
<Cover>
<svelte:fragment slot="header">
<CoverTitle
href={`${base}/project-${page.params.region}-${page.params.project}/auth/teams`}>
<CoverTitle href={back}>
{$team?.name}
</CoverTitle>
<Id value={$team?.$id} event="team">{$team?.$id}</Id>
@@ -6,7 +6,8 @@
import { Cover, CoverTitle } from '$lib/layout';
import { user } from './store';
const path = `${base}/project-${page.params.region}-${page.params.project}/auth/user-${page.params.user}`;
export let back = `${base}/project-${page.params.region}-${page.params.project}/auth`;
export let path = `${base}/project-${page.params.region}-${page.params.project}/auth/user-${page.params.user}`;
const tabs = [
{
href: path,
@@ -44,7 +45,7 @@
<Cover>
<svelte:fragment slot="header">
<CoverTitle href={`${base}/project-${page.params.region}-${page.params.project}/auth`}>
<CoverTitle href={back}>
{$user.name ? $user.name : '-'}
</CoverTitle>
<Id value={$user.$id} event="user">{$user.$id}</Id>
@@ -4,6 +4,7 @@
import type { Models } from '@appwrite.io/console';
import { Container } from '$lib/layout';
import View from './view.svelte';
import { canWriteDatabases } from '$lib/stores/roles';
export let data;
const getDatabaseUrl = (database: Models.Database, firstTableId?: string | null) => {
@@ -14,6 +15,7 @@
<Container>
<View
canWriteDatabases={$canWriteDatabases}
databases={data.databases}
tables={data.tables}
policies={data.policies}
@@ -4,6 +4,7 @@
import type { Models } from '@appwrite.io/console';
import { Container } from '$lib/layout';
import View from './view.svelte';
import { canWriteTables } from '$lib/stores/roles';
export let data;
const createTableUrl = (table: Models.Table) => {
@@ -13,6 +14,7 @@
<Container>
<View
canWriteTables={$canWriteTables}
tables={data.tables}
limit={data.limit}
offset={data.offset}
@@ -9,7 +9,8 @@
const projectId = page.params.project;
const databaseId = page.params.database;
const path = `${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}`;
export let path = `${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}`;
export let back = `${base}/project-${page.params.region}-${projectId}/databases`;
const tabs = [
{
href: path,
@@ -40,7 +41,7 @@
<Cover expanded>
<svelte:fragment slot="header">
<CoverTitle href={`${base}/project-${page.params.region}-${projectId}/databases`}>
<CoverTitle href={back}>
{$database.name}
</CoverTitle>
<Id value={$database.$id}>{$database.$id}</Id>
@@ -1,252 +1,8 @@
<script lang="ts">
import { Filters, hasPageQueries, queries } from '$lib/components/filters';
import ViewSelector from '$lib/components/viewSelector.svelte';
import { Button } from '$lib/elements/forms';
import type { Column, ColumnType } from '$lib/helpers/types';
import { Container } from '$lib/layout';
import { preferences } from '$lib/stores/preferences';
import { canWriteTables, canWriteRows } from '$lib/stores/roles';
import { Icon, Layout, Divider } from '@appwrite.io/pink-svelte';
import View from './view.svelte';
import type { PageData } from './$types';
import {
table,
tableColumns,
isCsvImportInProgress,
showRowCreateSheet,
showCreateColumnSheet,
type Columns,
randomDataModalState,
expandTabs
} from './store';
import SpreadSheet from './spreadsheet.svelte';
import { writable } from 'svelte/store';
import FilePicker from '$lib/components/filePicker.svelte';
import { page } from '$app/state';
import { sdk } from '$lib/stores/sdk';
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 type { Models } from '@appwrite.io/console';
import EmptySheet from './layout/emptySheet.svelte';
import CreateRow from './rows/create.svelte';
import { onDestroy } from 'svelte';
export let data: PageData;
let showImportCSV = false;
// todo: might need a type fix here.
const filterColumns = writable<Column[]>([]);
function createTableColumns(columns: Columns[], selected: string[] = []): Column[] {
return columns.map((column) => ({
id: column.key,
title: column.key,
type: column.type as ColumnType,
hide: !!selected?.includes(column.key),
array: column?.array,
format: 'format' in column && column?.format === 'enum' ? column.format : null,
elements: 'elements' in column ? column.elements : null
}));
}
$: selected = preferences.getCustomTableColumns(page.params.table);
$: if ($table.columns) {
const freshColumns = createTableColumns($table.columns, selected);
tableColumns.set(freshColumns);
filterColumns.set(freshColumns.filter((column) => !column.isAction));
}
$: hasColumns = !!$table.columns.length;
$: hasValidColumns = $table?.columns?.some((col) => col.status === 'available');
async function onSelect(file: Models.File, localFile = false) {
$isCsvImportInProgress = true;
try {
await sdk
.forProject(page.params.region, page.params.project)
.migrations.createCsvMigration({
bucketId: file.bucketId,
fileId: file.$id,
resourceId: `${page.params.database}:${page.params.table}`,
internalFile: localFile
});
addNotification({
type: 'success',
message: 'Rows import from csv has started'
});
trackEvent(Submit.DatabaseImportCsv);
} catch (e) {
trackError(e, Submit.DatabaseImportCsv);
addNotification({
type: 'error',
message: e.message
});
} finally {
$isCsvImportInProgress = false;
}
}
onDestroy(() => ($showCreateColumnSheet.show = false));
</script>
{#key page.params.table}
<Container expanded expandHeightButton style="background: var(--bgcolor-neutral-primary)">
<Layout.Stack direction="column" gap="xl">
<Layout.Stack direction="row" justifyContent="space-between">
<Layout.Stack direction="row" gap="s">
<ViewSelector
onlyIcon
ui="new"
view={data.view}
columns={tableColumns}
hideView
showAnyway
isCustomTable />
<Filters
onlyIcon
query={data.query}
columns={filterColumns}
disabled={!(hasColumns && hasValidColumns)}
analyticsSource="database_rows" />
</Layout.Stack>
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
<Button
secondary
event={Click.DatabaseImportCsv}
disabled={!(hasColumns && hasValidColumns)}
on:click={() => (showImportCSV = true)}>
Import CSV
</Button>
{#if !$isSmallViewport}
<Button
secondary
event="create_row"
disabled={!(hasColumns && hasValidColumns)}
on:click={() => ($showRowCreateSheet.show = true)}>
<Icon icon={IconPlus} slot="start" size="s" />
Create row
</Button>
<Button
icon
size="s"
secondary
class="small-button-dimensions"
on:click={() => {
$expandTabs = !$expandTabs;
preferences.setKey('tableHeaderExpanded', $expandTabs);
}}>
<Icon icon={!$expandTabs ? IconChevronDown : IconChevronUp} size="s" />
</Button>
{/if}
</Layout.Stack>
</Layout.Stack>
{#if $isSmallViewport}
<Button
secondary
event="create_row"
disabled={!(hasColumns && hasValidColumns)}
on:click={() => ($showRowCreateSheet.show = true)}>
<Icon icon={IconPlus} slot="start" size="s" />
Create row
</Button>
{/if}
</Layout.Stack>
</Container>
<div class="databases-spreadsheet">
{#if hasColumns && hasValidColumns}
{#if data.rows.total}
<Divider />
<SpreadSheet {data} bind:showRowCreateSheet={$showRowCreateSheet} />
{:else if $hasPageQueries}
<EmptySheet
mode="rows-filtered"
title="There are no rows that match your filters"
customColumns={createTableColumns($table.columns, selected)}
actions={{
primary: {
text: 'Clear filters',
onClick: () => {
queries.clearAll();
queries.apply();
trackEvent(Submit.FilterClear, {
source: 'database_rows'
});
}
}
}} />
{:else}
<EmptySheet
mode="rows"
customColumns={createTableColumns($table.columns, selected)}
showActions={$canWriteRows}
actions={{
primary: {
text: 'Create rows',
onClick: () => {
$showRowCreateSheet.show = true;
}
},
random: {
onClick: () => {
$randomDataModalState.show = true;
}
}
}} />
{/if}
{:else}
<EmptySheet
mode="rows"
title="You have no columns yet"
showActions={$canWriteTables}
actions={{
primary: {
text: 'Create column',
onClick: async () => {
$showCreateColumnSheet.show = true;
}
},
random: {
onClick: () => {
$randomDataModalState.show = true;
}
}
}} />
{/if}
</div>
{/key}
{#if showImportCSV}
<!-- CSVs can be text/plain or text/csv sometimes! -->
<FilePicker
{onSelect}
showLocalFileBucket
localFileBucketTitle="Upload CSV file"
mimeTypeQuery="text/"
allowedExtension="csv"
bind:show={showImportCSV}
gridImageDimensions={{
imageHeight: 32,
imageWidth: 32
}} />
{/if}
<CreateRow
table={$table}
bind:showSheet={$showRowCreateSheet.show}
bind:existingData={$showRowCreateSheet.row} />
<style>
:global(.small-button-dimensions) {
width: 32px !important;
height: 32px !important;
}
</style>
<View {data} />
@@ -14,9 +14,11 @@
const tableId = $derived(page.params.table);
const path = $derived(
const computedPath = $derived(
`${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}/table-${tableId}`
);
let { path: _path, back: _back } = $props();
const path = $derived(_path ?? computedPath);
const tabs = $derived(
[
@@ -57,9 +59,10 @@
].filter((tab) => !tab.disabled)
);
const link = $derived(
const computedBack = $derived(
`${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}`
);
const back = $derived(_back ?? computedBack);
const nonSheetPages = $derived.by(() => {
const endings = ['table-[table]', 'table-[table]/columns', 'table-[table]/indexes'];
@@ -79,7 +82,7 @@
<Cover animate expanded collapsed={!$expandTabs} blocksize={$expandTabs ? '152px' : '90px'}>
<svelte:fragment slot="header">
<Layout.Stack direction="row" alignContent="center" alignItems="center" inline>
<AnimatedTitle href={link} collapsed={!$expandTabs}>
<AnimatedTitle href={back} collapsed={!$expandTabs}>
{$table?.name}
</AnimatedTitle>
@@ -0,0 +1,274 @@
<script lang="ts">
import { Filters, hasPageQueries, queries } from '$lib/components/filters';
import ViewSelector from '$lib/components/viewSelector.svelte';
import { Button } from '$lib/elements/forms';
import type { Column, ColumnType } from '$lib/helpers/types';
import { Container } from '$lib/layout';
import { preferences } from '$lib/stores/preferences';
import { canWriteTables, canWriteRows } from '$lib/stores/roles';
import { Icon, Layout, Divider } from '@appwrite.io/pink-svelte';
import { View } from '$lib/helpers/load';
import {
table,
tableColumns,
isCsvImportInProgress,
showRowCreateSheet,
showCreateColumnSheet,
type Columns,
randomDataModalState,
expandTabs
} from './store';
import SpreadSheet from './spreadsheet.svelte';
import { writable } from 'svelte/store';
import FilePicker from '$lib/components/filePicker.svelte';
import { page } from '$app/state';
import { sdk } from '$lib/stores/sdk';
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 type { Models } from '@appwrite.io/console';
import EmptySheet from './layout/emptySheet.svelte';
import CreateRow from './rows/create.svelte';
import { onDestroy } from 'svelte';
type Props = {
data: {
offset: number;
limit: number;
view: string;
query: string;
currentSort: {
column: string | number | string[] | null;
direction: string;
};
rows: Models.RowList<Models.DefaultRow>;
organization?: { $id: string };
project?: { teamId: string };
[key: string]: unknown;
};
};
let { data }: Props = $props();
let showImportCSV = $state(false);
// todo: might need a type fix here.
const filterColumns = writable<Column[]>([]);
function createTableColumns(columns: Columns[], selected: string[] = []): Column[] {
return columns.map((column) => ({
id: column.key,
title: column.key,
type: column.type as ColumnType,
hide: !!selected?.includes(column.key),
array: column?.array,
format: 'format' in column && column?.format === 'enum' ? column.format : null,
elements: 'elements' in column ? column.elements : null
}));
}
const selected = $derived(preferences.getCustomTableColumns(page.params.table));
$effect(() => {
if ($table.columns) {
const freshColumns = createTableColumns($table.columns, selected);
tableColumns.set(freshColumns);
filterColumns.set(freshColumns.filter((column) => !column.isAction));
}
});
const hasColumns = $derived(!!$table.columns.length);
const hasValidColumns = $derived($table?.columns?.some((col) => col.status === 'available'));
async function onSelect(file: Models.File, localFile = false) {
$isCsvImportInProgress = true;
try {
await sdk
.forProject(page.params.region, page.params.project)
.migrations.createCsvMigration({
bucketId: file.bucketId,
fileId: file.$id,
resourceId: `${page.params.database}:${page.params.table}`,
internalFile: localFile
});
addNotification({
type: 'success',
message: 'Rows import from csv has started'
});
trackEvent(Submit.DatabaseImportCsv);
} catch (e) {
trackError(e, Submit.DatabaseImportCsv);
addNotification({
type: 'error',
message: e.message
});
} finally {
$isCsvImportInProgress = false;
}
}
onDestroy(() => ($showCreateColumnSheet.show = false));
</script>
{#key page.params.table}
<Container expanded expandHeightButton style="background: var(--bgcolor-neutral-primary)">
<Layout.Stack direction="column" gap="xl">
<Layout.Stack direction="row" justifyContent="space-between">
<Layout.Stack direction="row" gap="s">
<ViewSelector
onlyIcon
ui="new"
view={data.view as View}
columns={tableColumns}
hideView
showAnyway
isCustomTable />
<Filters
onlyIcon
query={data.query}
columns={filterColumns}
disabled={!(hasColumns && hasValidColumns)}
analyticsSource="database_rows" />
</Layout.Stack>
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
<Button
secondary
event={Click.DatabaseImportCsv}
disabled={!(hasColumns && hasValidColumns)}
on:click={() => (showImportCSV = true)}>
Import CSV
</Button>
{#if !$isSmallViewport}
<Button
secondary
event="create_row"
disabled={!(hasColumns && hasValidColumns)}
on:click={() => ($showRowCreateSheet.show = true)}>
<Icon icon={IconPlus} slot="start" size="s" />
Create row
</Button>
<Button
icon
size="s"
secondary
class="small-button-dimensions"
on:click={() => {
$expandTabs = !$expandTabs;
preferences.setKey('tableHeaderExpanded', $expandTabs);
}}>
<Icon icon={!$expandTabs ? IconChevronDown : IconChevronUp} size="s" />
</Button>
{/if}
</Layout.Stack>
</Layout.Stack>
{#if $isSmallViewport}
<Button
secondary
event="create_row"
disabled={!(hasColumns && hasValidColumns)}
on:click={() => ($showRowCreateSheet.show = true)}>
<Icon icon={IconPlus} slot="start" size="s" />
Create row
</Button>
{/if}
</Layout.Stack>
</Container>
<div class="databases-spreadsheet">
{#if hasColumns && hasValidColumns}
{#if data.rows.total}
<Divider />
<SpreadSheet
data={data as unknown as import('./$types.js').PageData}
bind:showRowCreateSheet={$showRowCreateSheet} />
{:else if $hasPageQueries}
<EmptySheet
mode="rows-filtered"
title="There are no rows that match your filters"
customColumns={createTableColumns($table.columns, selected)}
actions={{
primary: {
text: 'Clear filters',
onClick: () => {
queries.clearAll();
queries.apply();
trackEvent(Submit.FilterClear, {
source: 'database_rows'
});
}
}
}} />
{:else}
<EmptySheet
mode="rows"
customColumns={createTableColumns($table.columns, selected)}
showActions={$canWriteRows}
actions={{
primary: {
text: 'Create rows',
onClick: () => {
$showRowCreateSheet.show = true;
}
},
random: {
onClick: () => {
$randomDataModalState.show = true;
}
}
}} />
{/if}
{:else}
<EmptySheet
mode="rows"
title="You have no columns yet"
showActions={$canWriteTables}
actions={{
primary: {
text: 'Create column',
onClick: async () => {
$showCreateColumnSheet.show = true;
}
},
random: {
onClick: () => {
$randomDataModalState.show = true;
}
}
}} />
{/if}
</div>
{/key}
{#if showImportCSV}
<!-- CSVs can be text/plain or text/csv sometimes! -->
<FilePicker
{onSelect}
showLocalFileBucket
localFileBucketTitle="Upload CSV file"
mimeTypeQuery="text/"
allowedExtension="csv"
bind:show={showImportCSV}
gridImageDimensions={{
imageHeight: 32,
imageWidth: 32
}} />
{/if}
<CreateRow
table={$table}
bind:showSheet={$showRowCreateSheet.show}
bind:existingData={$showRowCreateSheet.row} />
<style>
:global(.small-button-dimensions) {
width: 32px !important;
height: 32px !important;
}
</style>
@@ -12,7 +12,6 @@
import { Button } from '$lib/elements/forms';
import { showCreate, tableViewColumns } from './store';
import { Card, Empty, Icon, Layout, Table as PinkTable } from '@appwrite.io/pink-svelte';
import { canWriteTables } from '$lib/stores/roles';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import type { Models } from '@appwrite.io/console';
import { app } from '$lib/stores/app';
@@ -25,6 +24,7 @@
offset,
view,
search,
canWriteTables,
createTableUrl
}: {
tables: { total: number; tables: Models.Table[] };
@@ -32,11 +32,13 @@
offset: number;
view: View;
search: string | null;
canWriteTables: boolean;
createTableUrl: (table: Models.Table) => string;
} = $props();
const clearSearchHref = page.url.pathname;
const databaseId = page.params.database;
$inspect($showCreate);
</script>
<Layout.Stack direction="row" justifyContent="space-between">
@@ -51,7 +53,7 @@
hideColumns={!tables.total}
hideView={!tables.total} />
{#if $canWriteTables}
{#if canWriteTables}
<Button event="create_table" on:click={() => ($showCreate = true)}>
<Icon icon={IconPlus} slot="start" size="s" />
Create table
@@ -63,7 +65,7 @@
{#if tables.total}
{#if view === 'grid'}
<CardContainer
disableEmpty={!$canWriteTables}
disableEmpty={!canWriteTables}
total={tables.total}
{offset}
event="table"
@@ -123,7 +125,7 @@
text
event="empty_documentation"
ariaLabel={`create table`}>Documentation</Button>
{#if $canWriteTables}
{#if canWriteTables}
<Button
secondary
on:click={() => {
@@ -7,7 +7,7 @@
import { Typography } from '@appwrite.io/pink-svelte';
const projectId = page.params.project;
const path = `${base}/project-${page.params.region}-${projectId}/databases`;
export let path = `${base}/project-${page.params.region}-${projectId}/databases`;
const tabs = [
{
href: path,
@@ -9,7 +9,6 @@
CardContainer,
GridItem1
} from '$lib/components';
import { canWriteDatabases } from '$lib/stores/roles';
import { columns } from './store';
import { Icon, Layout, Table as PinkTable, Tooltip } from '@appwrite.io/pink-svelte';
import Create from './create.svelte';
@@ -31,6 +30,7 @@
offset,
view,
search,
canWriteDatabases,
getDatabaseUrl
}: {
databases: { total: number; databases: Models.Database[] };
@@ -41,6 +41,7 @@
offset: number;
view: View;
search: string | null;
canWriteDatabases: boolean;
getDatabaseUrl: (database: Models.Database, firstTableId?: string | null) => string | null;
} = $props();
@@ -69,8 +70,8 @@
</Layout.Stack>
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
<ViewSelector {columns} {view} hideColumns={!databases.total} hideView={!databases.total} />
{#if $canWriteDatabases}
<Button event="create_database">
{#if canWriteDatabases}
<Button event="create_database" on:click={() => (showCreate = true)}>
<Icon icon={IconPlus} slot="start" size="s" />
Create database
</Button>
@@ -81,7 +82,7 @@
{#if databases.total}
{#if view === 'grid'}
<CardContainer
disableEmpty={!$canWriteDatabases}
disableEmpty={!canWriteDatabases}
total={databases.total}
{offset}
event="database"
@@ -176,7 +177,7 @@
single
href="https://appwrite.io/docs/products/databases/databases"
target="database"
allowCreate={$canWriteDatabases} />
allowCreate={canWriteDatabases} />
{/if}
<Create bind:showCreate on:created={onCreated} />
@@ -6,7 +6,7 @@
import { Cover } from '$lib/layout';
import { Typography } from '@appwrite.io/pink-svelte';
const path = `${base}/project-${page.params.region}-${page.params.project}/messaging`;
export let path = `${base}/project-${page.params.region}-${page.params.project}/messaging`;
const tabs = [
{
href: path,
@@ -9,7 +9,7 @@
import { isCloud } from '$lib/system';
import { Typography } from '@appwrite.io/pink-svelte';
const path = `${base}/project-${page.params.region}-${page.params.project}/settings`;
export let path = `${base}/project-${page.params.region}-${page.params.project}/settings`;
const tabs: TabElement[] = [
{
href: path,
@@ -6,11 +6,12 @@
import { webhook } from './store';
const projectId = page.params.project;
export let back = `${base}/project-${page.params.region}-${projectId}/settings/webhooks`;
</script>
<Cover>
<svelte:fragment slot="header">
<CoverTitle href={`${base}/project-${page.params.region}-${projectId}/settings/webhooks`}>
<CoverTitle href={back}>
{$webhook?.name}
</CoverTitle>
<Id value={$webhook?.$id} event="webhook">{$webhook?.$id}</Id>
@@ -7,12 +7,12 @@
const projectId = page.params.project;
const bucketId = page.params.bucket;
export let back = `${base}/project-${page.params.region}-${projectId}/storage/bucket-${bucketId}`;
</script>
<Cover>
<svelte:fragment slot="header">
<CoverTitle
href={`${base}/project-${page.params.region}-${projectId}/storage/bucket-${bucketId}`}>
<CoverTitle href={back}>
{$file?.name}
</CoverTitle>
<Id value={$file?.$id} event="file">{$file?.$id}</Id>
@@ -9,7 +9,8 @@
const projectId = page.params.project;
const bucketId = page.params.bucket;
const path = `${base}/project-${page.params.region}-${projectId}/storage/bucket-${bucketId}`;
export let path = `${base}/project-${page.params.region}-${projectId}/storage/bucket-${bucketId}`;
export let back = `${base}/project-${page.params.region}-${projectId}/storage`;
const tabs = [
{
href: path,
@@ -34,7 +35,7 @@
<Cover>
<svelte:fragment slot="header">
<CoverTitle href={`${base}/project-${page.params.region}-${projectId}/storage`}>
<CoverTitle href={back}>
{$bucket?.name}
</CoverTitle>
{#if $bucket?.$id}
@@ -6,7 +6,7 @@
import { Cover } from '$lib/layout';
import { Typography } from '@appwrite.io/pink-svelte';
const path = `${base}/project-${page.params.region}-${page.params.project}/storage`;
export let path = `${base}/project-${page.params.region}-${page.params.project}/storage`;
const tabs = [
{
href: path,
+12
View File
@@ -0,0 +1,12 @@
<script>
import { page } from '$app/state';
let { children } = $props();
</script>
{#if page.data.header}
{@const Header = page.data.header}
<Header path={page.data.path} back={page.data.back} />
{/if}
{@render children()}
@@ -0,0 +1,18 @@
import type { LayoutLoad } from './$types';
import { sdk } from '$lib/stores/sdk';
export const load: LayoutLoad = async ({ params }) => {
const project = await sdk.forConsole.projects.get({ projectId: params.project });
const organization = await sdk.forConsole.teams.get({ teamId: project.teamId });
const currentPlan = await sdk.forConsole.billing.getOrganizationPlan(organization.$id);
const { roles, scopes } = await sdk.forConsole.billing.getRoles(organization.$id);
return {
header: null,
project,
organization,
currentPlan,
roles,
scopes
};
};
@@ -1,8 +1,10 @@
import type { LayoutLoad } from './$types';
import { sdk } from '$lib/stores/sdk';
import { base } from '$app/paths';
import Header from '$routes/(console)/project-[region]-[project]/auth/header.svelte';
export const load: LayoutLoad = async ({ params }) => {
// Minimal layout data for embeds; no UI wrapping.
const project = await sdk.forConsole.projects.get(params.project);
return { project } as const;
return {
header: Header,
path: `${base}/embed/project-${params.region}-${params.project}/auth`
};
};
@@ -2,19 +2,19 @@
import { base } from '$app/paths';
import { page } from '$app/state';
import type { Models } from '@appwrite.io/console';
import { Layout } from '@appwrite.io/pink-svelte';
import View from '$routes/(console)/project-[region]-[project]/auth/view.svelte';
import Container from '$lib/layout/container.svelte';
let { data } = $props();
const createUserUrl = (user: Models.User<{}>) =>
`${base}/embed/project-${page.params.region}-${page.params.project}/auth/user-${user.$id}`;
</script>
<Layout.Stack>
<Container>
<View
users={data.users}
limit={data.limit}
offset={data.offset}
search={data.search}
{createUserUrl} />
</Layout.Stack>
</Container>
@@ -1,5 +1,5 @@
<script lang="ts">
import { Layout } from '@appwrite.io/pink-svelte';
import Container from '$lib/layout/container.svelte';
import UpdatePasswordDictionary from '$routes/(console)/project-[region]-[project]/auth/security/updatePasswordDictionary.svelte';
import UpdatePasswordHistory from '$routes/(console)/project-[region]-[project]/auth/security/updatePasswordHistory.svelte';
import UpdatePersonalDataCheck from '$routes/(console)/project-[region]-[project]/auth/security/updatePersonalDataCheck.svelte';
@@ -11,7 +11,7 @@
import UpdateSessionInvalidation from '$routes/(console)/project-[region]-[project]/auth/security/updateSessionInvalidation.svelte';
</script>
<Layout.Stack>
<Container>
<UpdateUsersLimit />
<UpdateSessionLength />
<UpdateSessionsLimit />
@@ -21,4 +21,4 @@
<UpdateSessionAlerts />
<UpdateSessionInvalidation />
<UpdateMembershipPrivacy />
</Layout.Stack>
</Container>
@@ -2,19 +2,19 @@
import { base } from '$app/paths';
import { page } from '$app/state';
import type { Models } from '@appwrite.io/console';
import { Layout } from '@appwrite.io/pink-svelte';
import View from '$routes/(console)/project-[region]-[project]/auth/teams/view.svelte';
import Container from '$lib/layout/container.svelte';
let { data } = $props();
const createTeamUrl = (team: Models.Team<Record<string, unknown>>) =>
`${base}/embed/project-${page.params.region}-${page.params.project}/auth/teams/team-${team.$id}`;
</script>
<Layout.Stack>
<Container>
<View
teams={data.teams}
limit={data.limit}
offset={data.offset}
search={data.search}
{createTeamUrl} />
</Layout.Stack>
</Container>
@@ -0,0 +1,17 @@
import type { PageLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/auth/teams/team-[team]/header.svelte';
import { sdk } from '$lib/stores/sdk';
import { base } from '$app/paths';
export const load: PageLoad = async ({ params }) => {
const team = await sdk
.forProject(params.region, params.project)
.teams.get({ teamId: params.team });
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/auth/teams`,
path: `${base}/embed/project-${params.region}-${params.project}/auth/teams/team-${params.team}`,
team
};
};
@@ -0,0 +1,6 @@
<script lang="ts">
import TeamActivityPage from '$routes/(console)/project-[region]-[project]/auth/teams/team-[team]/activity/+page.svelte';
let { data } = $props();
</script>
<TeamActivityPage data={data as any} />
@@ -0,0 +1,32 @@
import type { PageLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/auth/teams/team-[team]/header.svelte';
import { base } from '$app/paths';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import { Query } from '@appwrite.io/console';
export const load: PageLoad = async ({ params, url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
const [team, logs] = await Promise.all([
sdk.forProject(params.region, params.project).teams.get({ teamId: params.team }),
sdk.forProject(params.region, params.project).teams.listLogs({
teamId: params.team,
queries: [Query.limit(limit), Query.offset(offset)]
})
]);
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/auth/teams`,
path: `${base}/embed/project-${params.region}-${params.project}/auth/teams/team-${params.team}`,
team,
offset,
limit,
logs
};
};
@@ -0,0 +1,6 @@
<script lang="ts">
import TeamMembersPage from '$routes/(console)/project-[region]-[project]/auth/teams/team-[team]/members/+page.svelte';
let { data } = $props();
</script>
<TeamMembersPage data={data as any} />
@@ -0,0 +1,37 @@
import type { PageLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/auth/teams/team-[team]/header.svelte';
import { base } from '$app/paths';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, getSearch, pageToOffset } from '$lib/helpers/load';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { Query } from '@appwrite.io/console';
export const load: PageLoad = async ({ params, depends, url, route }) => {
depends(Dependencies.MEMBERSHIPS);
const page = getPage(url);
const search = getSearch(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
const [team, memberships] = await Promise.all([
sdk.forProject(params.region, params.project).teams.get({ teamId: params.team }),
sdk.forProject(params.region, params.project).teams.listMemberships({
teamId: params.team,
queries: [Query.limit(limit), Query.offset(offset), Query.orderDesc('')],
search
})
]);
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/auth/teams`,
path: `${base}/embed/project-${params.region}-${params.project}/auth/teams/team-${params.team}`,
team,
offset,
search,
limit,
memberships
};
};
@@ -1,5 +1,7 @@
import type { PageLoad } from './$types';
import { sdk } from '$lib/stores/sdk';
import Header from '$routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte';
import { base } from '$app/paths';
export const load: PageLoad = async ({ params }) => {
const [user, userFactors] = await Promise.all([
@@ -7,5 +9,11 @@ export const load: PageLoad = async ({ params }) => {
sdk.forProject(params.region, params.project).users.listMfaFactors(params.user)
]);
return { user, userFactors };
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/auth`,
path: `${base}/embed/project-${params.region}-${params.project}/auth/user-${params.user}`,
user,
userFactors
};
};
@@ -0,0 +1,6 @@
<script lang="ts">
import UserActivityPage from '$routes/(console)/project-[region]-[project]/auth/user-[user]/activity/+page.svelte';
let { data } = $props();
</script>
<UserActivityPage data={data as any} />
@@ -0,0 +1,32 @@
import type { PageLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte';
import { base } from '$app/paths';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { PAGE_LIMIT } from '$lib/constants';
import { Query } from '@appwrite.io/console';
export const load: PageLoad = async ({ params, url, route }) => {
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
const [user, logs] = await Promise.all([
sdk.forProject(params.region, params.project).users.get(params.user),
sdk.forProject(params.region, params.project).users.listLogs({
userId: params.user,
queries: [Query.limit(limit), Query.offset(offset)]
})
]);
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/auth`,
path: `${base}/embed/project-${params.region}-${params.project}/auth/user-${params.user}`,
user,
offset,
limit,
logs
};
};
@@ -0,0 +1,6 @@
<script lang="ts">
import UserIdentitiesPage from '$routes/(console)/project-[region]-[project]/auth/user-[user]/identities/+page.svelte';
let { data } = $props();
</script>
<UserIdentitiesPage data={data as any} />
@@ -0,0 +1,48 @@
import type { PageLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte';
import { base } from '$app/paths';
import { sdk } from '$lib/stores/sdk';
import { queries, queryParamToMap } from '$lib/components/filters';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { getLimit, getPage, getQuery, getSearch, pageToOffset } from '$lib/helpers/load';
import { Query } from '@appwrite.io/console';
export const load: PageLoad = async ({ params, url, route, depends }) => {
depends(Dependencies.USER_IDENTITIES);
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
const query = getQuery(url);
const search = getSearch(url);
const parsedQueries = queryParamToMap(query || '[]');
queries.set(parsedQueries);
const [user, identities] = await Promise.all([
sdk.forProject(params.region, params.project).users.get(params.user),
sdk.forProject(params.region, params.project).users.listIdentities({
queries: [
Query.equal('userId', params.user),
Query.limit(limit),
Query.offset(offset),
Query.orderDesc(''),
...parsedQueries.values()
],
search
})
]);
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/auth`,
path: `${base}/embed/project-${params.region}-${params.project}/auth/user-${params.user}`,
user,
offset,
limit,
query,
search,
identities
};
};
@@ -0,0 +1,6 @@
<script lang="ts">
import UserMembershipsPage from '$routes/(console)/project-[region]-[project]/auth/user-[user]/memberships/+page.svelte';
let { data } = $props();
</script>
<UserMembershipsPage data={data as any} />
@@ -0,0 +1,22 @@
import type { PageLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte';
import { sdk } from '$lib/stores/sdk';
import { base } from '$app/paths';
export const load: PageLoad = async ({ params }) => {
const [codes, user, memberships] = await Promise.all([
sdk.forProject(params.region, params.project).locale.listCodes(),
sdk.forProject(params.region, params.project).users.get(params.user),
sdk.forProject(params.region, params.project).users.listMemberships({ userId: params.user })
]);
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/auth`,
path: `${base}/embed/project-${params.region}-${params.project}/auth/user-${params.user}`,
user,
localeCodes: codes.localeCodes,
memberships
};
};
@@ -0,0 +1,6 @@
<script lang="ts">
import UserSessionsPage from '$routes/(console)/project-[region]-[project]/auth/user-[user]/sessions/+page.svelte';
let { data } = $props();
</script>
<UserSessionsPage data={data as any} />
@@ -0,0 +1,23 @@
import type { PageLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte';
import { base } from '$app/paths';
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
export const load: PageLoad = async ({ params, depends }) => {
depends(Dependencies.SESSIONS);
const [user, sessions] = await Promise.all([
sdk.forProject(params.region, params.project).users.get(params.user),
sdk.forProject(params.region, params.project).users.listSessions({ userId: params.user })
]);
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/auth`,
path: `${base}/embed/project-${params.region}-${params.project}/auth/user-${params.user}`,
user,
sessions
};
};
@@ -0,0 +1,6 @@
<script lang="ts">
import UserTargetsPage from '$routes/(console)/project-[region]-[project]/auth/user-[user]/targets/+page.svelte';
let { data } = $props();
</script>
<UserTargetsPage data={data as any} />
@@ -0,0 +1,64 @@
import type { PageLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte';
import { base } from '$app/paths';
import { sdk } from '$lib/stores/sdk';
import { queries, queryParamToMap } from '$lib/components/filters';
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
import { getLimit, getPage, getQuery, pageToOffset } from '$lib/helpers/load';
import { Query, type Models } from '@appwrite.io/console';
export const load: PageLoad = async ({ params, url, route, depends }) => {
depends(Dependencies.USER_TARGETS);
const page = getPage(url);
const limit = getLimit(url, route, PAGE_LIMIT);
const offset = pageToOffset(page, limit);
const query = getQuery(url);
const parsedQueries = queryParamToMap(query || '[]');
queries.set(parsedQueries);
const [user, targets] = await Promise.all([
sdk.forProject(params.region, params.project).users.get(params.user),
sdk.forProject(params.region, params.project).users.listTargets({
userId: params.user,
queries: [
Query.limit(limit),
Query.offset(offset),
Query.orderDesc(''),
...parsedQueries.values()
]
})
]);
const promisesById: Record<string, Promise<Models.Provider>> = {};
targets.targets.forEach((target) => {
if (target.providerId && !promisesById[target.providerId]) {
promisesById[target.providerId] = sdk
.forProject(params.region, params.project)
.messaging.getProvider({ providerId: target.providerId });
}
});
const providersById: Record<string, Models.Provider> = {};
const resolved = await Promise.allSettled(Object.values(promisesById));
resolved.forEach((result) => {
if (result.status === 'fulfilled') {
const provider = result.value;
providersById[provider.$id] = provider;
}
});
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/auth`,
path: `${base}/embed/project-${params.region}-${params.project}/auth/user-${params.user}`,
user,
offset,
limit,
query,
targets,
providersById
};
};
@@ -1,6 +1,12 @@
import type { LayoutLoad } from './$types';
import { base } from '$app/paths';
import Header from '$routes/(console)/project-[region]-[project]/databases/header.svelte';
export const load: LayoutLoad = async ({ parent }) => {
export const load: LayoutLoad = async ({ parent, params }) => {
const { project } = await parent();
return { project };
return {
project,
header: Header,
path: `${base}/embed/project-${params.region}-${params.project}/databases`
};
};
@@ -2,7 +2,7 @@
import { base } from '$app/paths';
import { page } from '$app/state';
import type { Models } from '@appwrite.io/console';
import { Layout } from '@appwrite.io/pink-svelte';
import Container from '$lib/layout/container.svelte';
import View from '$routes/(console)/project-[region]-[project]/databases/view.svelte';
let { data } = $props();
@@ -12,15 +12,16 @@
};
</script>
<Layout.Stack>
<Container>
<View
databases={data?.databases || { total: 0, databases: [] }}
tables={data?.tables || {}}
policies={data?.policies || {}}
lastBackups={data?.lastBackups || {}}
limit={data?.limit || 25}
offset={data?.offset || 0}
view={data?.view || 'grid'}
search={data?.search || null}
databases={data.databases}
tables={data.tables}
policies={data.policies}
lastBackups={data.lastBackups}
limit={data.limit}
offset={data.offset}
view={data.view}
search={data.search}
canWriteDatabases={true}
{getDatabaseUrl} />
</Layout.Stack>
</Container>
@@ -1,6 +1,8 @@
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import type { LayoutLoad } from './$types';
import { base } from '$app/paths';
import Header from '$routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte';
export const load: LayoutLoad = async ({ params, depends }) => {
depends(Dependencies.DATABASE);
@@ -10,6 +12,9 @@ export const load: LayoutLoad = async ({ params, depends }) => {
});
return {
header: Header,
path: `${base}/embed/project-${params.region}-${params.project}/databases/database-${params.database}`,
back: `${base}/embed/project-${params.region}-${params.project}/databases`,
database
};
};
@@ -3,15 +3,25 @@
import { page } from '$app/state';
import { Layout } from '@appwrite.io/pink-svelte';
import View from '$routes/(console)/project-[region]-[project]/databases/database-[database]/view.svelte';
import CreateTable from '$routes/(console)/project-[region]-[project]/databases/database-[database]/createTable.svelte';
import { showCreate } from '$routes/(console)/project-[region]-[project]/databases/database-[database]/store';
import type { Models } from '@appwrite.io/console';
import { goto } from '$app/navigation';
let { data } = $props();
const createTableUrl = (table) => {
function createTableUrl(table: Models.Table) {
return `${base}/embed/project-${page.params.region}-${page.params.project}/databases/database-${page.params.database}/table-${table.$id}`;
};
}
async function handleCreate(event: CustomEvent<Models.Table>) {
$showCreate = false;
await goto(createTableUrl(event.detail));
}
</script>
<Layout.Stack>
<View
canWriteTables
tables={data.tables}
limit={data.limit}
offset={data.offset}
@@ -19,3 +29,5 @@
search={data.search}
{createTableUrl} />
</Layout.Stack>
<CreateTable bind:showCreate={$showCreate} on:created={handleCreate} />
@@ -1,11 +1,16 @@
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import type { LayoutLoad } from './$types';
import { base } from '$app/paths';
import Header from '$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/header.svelte';
export const load: LayoutLoad = async ({ params, depends }) => {
depends(Dependencies.TABLE);
return {
header: Header,
path: `${base}/embed/project-${params.region}-${params.project}/databases/database-${params.database}/table-${params.table}`,
back: `${base}/embed/project-${params.region}-${params.project}/databases/database-${params.database}`,
table: await sdk.forProject(params.region, params.project).tablesDB.getTable({
databaseId: params.database,
tableId: params.table
@@ -1,9 +1,9 @@
<script lang="ts">
import { Layout } from '@appwrite.io/pink-svelte';
import TablePage from '$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte';
import View from '$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/view.svelte';
let { data } = $props();
</script>
<Layout.Stack>
<TablePage {data} />
<View {data} />
</Layout.Stack>
@@ -0,0 +1,10 @@
import type { LayoutLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/messaging/header.svelte';
import { base } from '$app/paths';
export const load: LayoutLoad = async ({ params }) => {
return {
header: Header,
path: `${base}/embed/project-${params.region}-${params.project}/messaging`
};
};
@@ -0,0 +1,11 @@
import type { LayoutLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/settings/header.svelte';
import { base } from '$app/paths';
export const load: LayoutLoad = async ({ params }) => {
return {
header: Header,
path: `${base}/embed/project-${params.region}-${params.project}/settings`
};
};
@@ -0,0 +1,13 @@
<script lang="ts">
import Container from '$lib/layout/container.svelte';
import UpdateName from '$routes/(console)/project-[region]-[project]/settings/updateName.svelte';
import DeleteProject from '$routes/(console)/project-[region]-[project]/settings/deleteProject.svelte';
import { canWriteProjects } from '$lib/stores/roles';
</script>
<Container>
<UpdateName />
{#if $canWriteProjects}
<DeleteProject />
{/if}
</Container>
@@ -0,0 +1,2 @@
export { load } from '$routes/(console)/project-[region]-[project]/settings/+page.ts';
@@ -0,0 +1,7 @@
<script lang="ts">
import DomainsPage from '$routes/(console)/project-[region]-[project]/settings/domains/+page.svelte';
let { data } = $props();
</script>
<DomainsPage {data} />
@@ -0,0 +1,2 @@
export { load } from '$routes/(console)/project-[region]-[project]/settings/domains/+page.ts';
@@ -0,0 +1,7 @@
<script lang="ts">
import AddDomainPage from '$routes/(console)/project-[region]-[project]/settings/domains/add-domain/+page.svelte';
let { data } = $props();
</script>
<AddDomainPage {data} />
@@ -0,0 +1,2 @@
export { load } from '$routes/(console)/project-[region]-[project]/settings/domains/add-domain/+page.ts';
@@ -0,0 +1,7 @@
<script lang="ts">
import VerifyDomainPage from '$routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.svelte';
let { data } = $props();
</script>
<VerifyDomainPage {data} />
@@ -0,0 +1,2 @@
export { load } from '$routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.ts';
@@ -0,0 +1,7 @@
<script lang="ts">
import MigrationsPage from '$routes/(console)/project-[region]-[project]/settings/migrations/+page.svelte';
let { data } = $props();
</script>
<MigrationsPage {data} />
@@ -0,0 +1,2 @@
export { load } from '$routes/(console)/project-[region]-[project]/settings/migrations/+page.ts';
@@ -0,0 +1,6 @@
<script lang="ts">
import SMTPPage from '$routes/(console)/project-[region]-[project]/settings/smtp/+page.svelte';
</script>
<SMTPPage />
@@ -0,0 +1,7 @@
<script lang="ts">
import UsagePage from '$routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.svelte';
let { data } = $props();
</script>
<UsagePage {data} />
@@ -0,0 +1,2 @@
export { load } from '$routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.ts';
@@ -1,6 +1,12 @@
import type { LayoutLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/storage/header.svelte';
import { base } from '$app/paths';
export const load: LayoutLoad = async ({ parent }) => {
export const load: LayoutLoad = async ({ parent, params }) => {
const { project } = await parent();
return { project };
return {
project,
header: Header,
path: `${base}/embed/project-${params.region}-${params.project}/storage`
};
};
@@ -2,7 +2,7 @@
import { base } from '$app/paths';
import { page } from '$app/state';
import type { Models } from '@appwrite.io/console';
import { Layout } from '@appwrite.io/pink-svelte';
import Container from '$lib/layout/container.svelte';
import View from '$routes/(console)/project-[region]-[project]/storage/view.svelte';
let { data } = $props();
@@ -12,7 +12,7 @@
};
</script>
<Layout.Stack>
<Container>
<View
buckets={data?.buckets || { total: 0, buckets: [] }}
limit={data?.limit || 25}
@@ -20,4 +20,4 @@
view={data?.view || 'grid'}
search={data?.search || null}
{createBucketUrl} />
</Layout.Stack>
</Container>
@@ -1,11 +1,16 @@
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import type { LayoutLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/header.svelte';
import { base } from '$app/paths';
export const load: LayoutLoad = async ({ params, depends }) => {
depends(Dependencies.BUCKET);
return {
header: Header,
path: `${base}/embed/project-${params.region}-${params.project}/storage/bucket-${params.bucket}`,
back: `${base}/embed/project-${params.region}-${params.project}/storage`,
bucket: await sdk.forProject(params.region, params.project).storage.getBucket({
bucketId: params.bucket
})
@@ -2,7 +2,7 @@
import { base } from '$app/paths';
import { page } from '$app/state';
import type { Models } from '@appwrite.io/console';
import { Layout } from '@appwrite.io/pink-svelte';
import Container from '$lib/layout/container.svelte';
import View from '$routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/view.svelte';
let { data } = $props();
@@ -12,11 +12,11 @@
};
</script>
<Layout.Stack>
<Container>
<View
files={data?.files || { total: 0, files: [] }}
limit={data?.limit || 25}
offset={data?.offset || 0}
search={data?.search || null}
{createFileUrl} />
</Layout.Stack>
</Container>
@@ -1,12 +1,16 @@
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import type { LayoutLoad } from './$types';
import Header from '$routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/header.svelte';
import { base } from '$app/paths';
export const load: LayoutLoad = async ({ params, depends }) => {
depends(Dependencies.FILE);
depends(Dependencies.FILE_TOKENS);
return {
header: Header,
back: `${base}/embed/project-${params.region}-${params.project}/storage/bucket-${params.bucket}`,
file: await sdk
.forProject(params.region, params.project)
.storage.getFile({ bucketId: params.bucket, fileId: params.file }),
@@ -1,10 +1,9 @@
<script lang="ts">
import { Layout } from '@appwrite.io/pink-svelte';
import FilePage from '$routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/+page.svelte';
let { data } = $props();
</script>
<Layout.Stack>
<FilePage {data} />
<FilePage />
<!-- Console page uses stores provided by layout; no props needed. -->
</Layout.Stack>
@@ -0,0 +1,7 @@
<script lang="ts">
import BucketSettingsPage from '$routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/+page.svelte';
let { data } = $props();
</script>
<BucketSettingsPage data={data as any} />
-3
View File
@@ -34,9 +34,6 @@ export default defineConfig({
'zrender'
]
},
server: {
port: 3000
},
test: {
projects: [
{