mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Add embedded route detection and styling
Here's a concise commit message that summarizes the changes: Add embedded route detection and UI styling Check if the current route is in the /embed/ path and style appropriately. Add embedded views for auth, messaging, databases, and storage sections.
This commit is contained in:
@@ -13,6 +13,12 @@
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover" data-loading="true">
|
||||
<script>
|
||||
// Check if this is an embedded route
|
||||
if (window.location.pathname.includes('/embed/')) {
|
||||
document.body.setAttribute('data-embed', 'true');
|
||||
document.documentElement.setAttribute('data-embed', 'true');
|
||||
}
|
||||
|
||||
let themeInUse = 'auto';
|
||||
const appwrite = localStorage.getItem('appwrite');
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export type Breadcrumb = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
export type View = 'list' | 'grid';
|
||||
export type View = 'table' | 'grid';
|
||||
|
||||
export type updateLayoutArguments = {
|
||||
header?: Component;
|
||||
|
||||
@@ -174,7 +174,7 @@ export async function confirmPayment(
|
||||
if (error) {
|
||||
throw error.message;
|
||||
}
|
||||
} catch (e) {
|
||||
} catch {
|
||||
addNotification({
|
||||
title: 'Error',
|
||||
message:
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
} from '@appwrite.io/pink-icons-svelte';
|
||||
import type { LayoutData } from './$types';
|
||||
|
||||
export let data: LayoutData;
|
||||
export let data: LayoutData & { currentOrgId?: string; allProjectsCount?: number };
|
||||
let emailBannerClosed = false;
|
||||
|
||||
function kebabToSentenceCase(str: string) {
|
||||
|
||||
@@ -15,7 +15,7 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => {
|
||||
const { plansInfo, organizations, preferences: prefs } = await parent();
|
||||
depends(Dependencies.PROJECT);
|
||||
|
||||
const project = await sdk.forConsole.projects.get({ projectId: params.project });
|
||||
const project = await sdk.forConsole.projects.get(params.project);
|
||||
project.region ??= 'default';
|
||||
|
||||
// fast path without a network call!
|
||||
@@ -27,7 +27,7 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => {
|
||||
|
||||
const [org, regionalConsoleVariables, rolesResult, organizationPlan] = await Promise.all([
|
||||
!organization
|
||||
? (sdk.forConsole.teams.get({ teamId: project.teamId }) as Promise<Organization>)
|
||||
? (sdk.forConsole.teams.get(project.teamId) as Promise<Organization>)
|
||||
: organization,
|
||||
sdk.forConsoleIn(project.region).console.variables(),
|
||||
isCloud ? sdk.forConsole.billing.getRoles(project.teamId) : null,
|
||||
|
||||
@@ -4,15 +4,23 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { Container } from '$lib/layout';
|
||||
import View from './view.svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
const createUserUrl = (user: Models.User<{}>) => `${base}/project-${page.params.region}-${page.params.project}/auth/user-${user.$id}`;
|
||||
</script>
|
||||
|
||||
<View
|
||||
users={{ total: data.users.total, users: data.users.users }}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
pageNum={data.page}
|
||||
search={data.search}
|
||||
/>
|
||||
<Container>
|
||||
<View
|
||||
users={{ total: data.users.total, users: data.users.users }}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
search={data.search}
|
||||
{createUserUrl}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
@@ -4,14 +4,22 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { Container } from '$lib/layout';
|
||||
import View from './view.svelte';
|
||||
export let data;
|
||||
|
||||
const createTeamUrl = (team: Models.Team<Record<string, unknown>>) => `${base}/project-${page.params.region}-${page.params.project}/auth/teams/team-${team.$id}`;
|
||||
</script>
|
||||
|
||||
<View
|
||||
teams={{ total: data.teams.total, teams: data.teams.teams }}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
pageNum={data.page}
|
||||
search={data.search}
|
||||
/>
|
||||
<Container>
|
||||
<View
|
||||
teams={{ total: data.teams.total, teams: data.teams.teams }}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
search={data.search}
|
||||
{createTeamUrl}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
@@ -12,24 +11,29 @@
|
||||
import DualTimeView from '$lib/components/dualTimeView.svelte';
|
||||
import CreateTeam from '../createTeam.svelte';
|
||||
|
||||
export let teams: { total: number; teams: Models.Team<Record<string, unknown>>[] };
|
||||
export let limit: number;
|
||||
export let offset: number;
|
||||
export const pageNum: number = 0;
|
||||
export let search: string | null;
|
||||
let {
|
||||
teams,
|
||||
limit,
|
||||
offset,
|
||||
search,
|
||||
createTeamUrl
|
||||
}: {
|
||||
teams: { total: number; teams: Models.Team<Record<string, unknown>>[] };
|
||||
limit: number;
|
||||
offset: number;
|
||||
search: string | null;
|
||||
createTeamUrl: (team: Models.Team<Record<string, unknown>>) => string;
|
||||
} = $props();
|
||||
|
||||
const clearSearchHref = `${base}/project-${page.params.region}-${page.params.project}/auth/teams`;
|
||||
const getTeamUrl = (t: Models.Team<Record<string, unknown>>) =>
|
||||
`${base}/project-${page.params.region}-${page.params.project}/auth/teams/team-${t.$id}`;
|
||||
const clearSearchHref = page.url.pathname;
|
||||
|
||||
let showCreateTeam = false;
|
||||
let showCreateTeam = $state(false);
|
||||
async function onTeamCreated(e: CustomEvent<Models.Team<Record<string, unknown>>>) {
|
||||
await goto(getTeamUrl(e.detail));
|
||||
await goto(createTeamUrl(e.detail));
|
||||
}
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<SearchQuery placeholder="Search by name" />
|
||||
</Layout.Stack>
|
||||
@@ -49,7 +53,7 @@
|
||||
<Table.Header.Cell {root}>Created</Table.Header.Cell>
|
||||
</svelte:fragment>
|
||||
{#each teams.teams as team}
|
||||
{@const href = getTeamUrl(team)}
|
||||
{@const href = createTeamUrl(team)}
|
||||
{#if href}
|
||||
<Table.Row.Link {root} href={href}>
|
||||
<Table.Cell {root}>
|
||||
@@ -99,6 +103,5 @@
|
||||
href="https://appwrite.io/docs/references/cloud/client-web/teams"
|
||||
target="team" />
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
<CreateTeam bind:showCreate={showCreateTeam} on:created={onTeamCreated} />
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { AvatarInitials, Copy, Empty, EmptySearch, PaginationWithLimit, SearchQuery } from '$lib/components';
|
||||
@@ -16,19 +15,25 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import CreateUser from './createUser.svelte';
|
||||
|
||||
export let users: { total: number; users: Models.User<{}>[] };
|
||||
export let limit: number;
|
||||
export let offset: number;
|
||||
export const pageNum: number = 0;
|
||||
export let search: string | null;
|
||||
let {
|
||||
users,
|
||||
limit,
|
||||
offset,
|
||||
search,
|
||||
createUserUrl
|
||||
}: {
|
||||
users: { total: number; users: Models.User<{}>[] };
|
||||
limit: number;
|
||||
offset: number;
|
||||
search: string | null;
|
||||
createUserUrl: (user: Models.User<{}>) => string;
|
||||
} = $props();
|
||||
|
||||
const clearSearchHref = `${base}/project-${page.params.region}-${page.params.project}/auth`;
|
||||
const getUserUrl = (u: Models.User<{}>) =>
|
||||
`${base}/project-${page.params.region}-${page.params.project}/auth/user-${u.$id}`;
|
||||
const clearSearchHref = page.url.pathname;
|
||||
|
||||
let showCreateUser = false;
|
||||
let showCreateUser = $state(false);
|
||||
async function onUserCreated(e: CustomEvent<Models.User<{}>>) {
|
||||
await goto(getUserUrl(e.detail));
|
||||
await goto(createUserUrl(e.detail));
|
||||
}
|
||||
|
||||
const columns = writable<Column[]>([
|
||||
@@ -42,8 +47,7 @@
|
||||
]);
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<SearchQuery placeholder="Search by name, email, phone, or ID" />
|
||||
</Layout.Stack>
|
||||
@@ -65,7 +69,7 @@
|
||||
</svelte:fragment>
|
||||
|
||||
{#each users.users as user}
|
||||
{@const href = getUserUrl(user)}
|
||||
{@const href = createUserUrl(user)}
|
||||
{#if href}
|
||||
<Table.Row.Link href={href} {root}>
|
||||
{#each $columns as { id } (id)}
|
||||
@@ -213,6 +217,5 @@
|
||||
allowCreate={true}
|
||||
on:click={() => (showCreateUser = true)} />
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
<CreateUser bind:showCreate={showCreateUser} on:created={onUserCreated} />
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { Container } from '$lib/layout';
|
||||
import View from './view.svelte';
|
||||
export let data;
|
||||
import { base } from "\$app/paths";
|
||||
import { page } from "\$app/state";
|
||||
|
||||
const getDatabaseUrl = (database: Models.Database, firstTableId?: string | null) => {
|
||||
const tableSegment = firstTableId ? `/table-${firstTableId}` : '';
|
||||
return `${base}/project-${page.params.region}-${page.params.project}/databases/database-${database.$id}${tableSegment}`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<View
|
||||
databases={data.databases}
|
||||
tables={data.tables}
|
||||
policies={data.policies}
|
||||
lastBackups={data.lastBackups}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
view={data.view}
|
||||
search={data.search}
|
||||
clearSearchHref={`${base}/project-${page.params.region}-${page.params.project}/databases`}
|
||||
/>
|
||||
<Container>
|
||||
<View
|
||||
databases={data.databases}
|
||||
tables={data.tables}
|
||||
policies={data.policies}
|
||||
lastBackups={data.lastBackups}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
view={data.view}
|
||||
search={data.search}
|
||||
{getDatabaseUrl}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
+18
-1
@@ -1,6 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { Container } from '$lib/layout';
|
||||
import View from './view.svelte';
|
||||
export let data;
|
||||
|
||||
const createTableUrl = (table: Models.Table) => {
|
||||
return `${base}/project-${page.params.region}-${page.params.project}/databases/database-${page.params.database}/table-${table.$id}`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<View tables={data.tables} limit={data.limit} offset={data.offset} view={data.view} search={data.search} />
|
||||
<Container>
|
||||
<View
|
||||
tables={data.tables}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
view={data.view}
|
||||
search={data.search}
|
||||
{createTableUrl}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
+22
-13
@@ -1,26 +1,36 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import { EmptySearch, PaginationWithLimit, SearchQuery, ViewSelector, Id, CardContainer, GridItem1 } from '$lib/components';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Container } from '$lib/layout';
|
||||
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';
|
||||
import { View } from '$lib/helpers/load';
|
||||
|
||||
export let tables: { total: number; tables: Models.Table[] };
|
||||
export let limit: number;
|
||||
export let offset: number;
|
||||
export let view: 'grid' | 'table';
|
||||
export let search: string | null;
|
||||
let {
|
||||
tables,
|
||||
limit,
|
||||
offset,
|
||||
view,
|
||||
search,
|
||||
createTableUrl
|
||||
}: {
|
||||
tables: { total: number; tables: Models.Table[] };
|
||||
limit: number;
|
||||
offset: number;
|
||||
view: View;
|
||||
search: string | null;
|
||||
createTableUrl: (table: Models.Table) => string;
|
||||
} = $props();
|
||||
|
||||
const clearSearchHref = page.url.pathname;
|
||||
const databaseId = page.params.database;
|
||||
</script>
|
||||
|
||||
<Container paddingInlineEnd={false}>
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<SearchQuery placeholder="Search by name or ID" />
|
||||
</Layout.Stack>
|
||||
@@ -41,7 +51,7 @@
|
||||
{#if view === 'grid'}
|
||||
<CardContainer disableEmpty={!$canWriteTables} total={tables.total} {offset} event="table" service="tables" on:click={() => ($showCreate = true)}>
|
||||
{#each tables.tables as table}
|
||||
<GridItem1 href={`${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}/table-${table.$id}`}>
|
||||
<GridItem1 href={createTableUrl(table)}>
|
||||
<svelte:fragment slot="title">{table.name}</svelte:fragment>
|
||||
<Id value={table.$id}>{table.$id}</Id>
|
||||
</GridItem1>
|
||||
@@ -55,7 +65,7 @@
|
||||
{/each}
|
||||
</svelte:fragment>
|
||||
{#each tables.tables as table (table.$id)}
|
||||
<PinkTable.Row.Link {root} href={`${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}/table-${table.$id}`}>
|
||||
<PinkTable.Row.Link {root} href={createTableUrl(table)}>
|
||||
{#each $tableViewColumns as column}
|
||||
<PinkTable.Cell column={column.id} {root}>
|
||||
{#if column.id === '$id'}
|
||||
@@ -77,7 +87,7 @@
|
||||
<PaginationWithLimit name="Tables" {limit} {offset} total={tables.total} />
|
||||
{:else if search}
|
||||
<EmptySearch target="tables" hidePagination>
|
||||
<Button size="s" secondary href={`${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}`}>Clear Search</Button>
|
||||
<Button size="s" secondary href={clearSearchHref}>Clear Search</Button>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Card.Base padding="none">
|
||||
@@ -92,4 +102,3 @@
|
||||
</Empty>
|
||||
</Card.Base>
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
@@ -1,39 +1,48 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import { Empty, PaginationWithLimit, SearchQuery, ViewSelector, Id, CardContainer, GridItem1 } from '$lib/components';
|
||||
import { canWriteDatabases } from '$lib/stores/roles';
|
||||
import { columns } from './store';
|
||||
import { Icon, Layout, Table as PinkTable, Badge, Tooltip, Button } from '@appwrite.io/pink-svelte';
|
||||
import { Icon, Layout, Table as PinkTable, Tooltip, Button } from '@appwrite.io/pink-svelte';
|
||||
import Create from './create.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { IconPlus, IconExclamation } from '@appwrite.io/pink-icons-svelte';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import EmptySearch from '$lib/components/emptySearch.svelte';
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import { View } from '$lib/helpers/load';
|
||||
|
||||
export let databases: { total: number; databases: Models.Database[] };
|
||||
export let tables: Record<string, string>;
|
||||
export let policies: Record<string, any>;
|
||||
export let lastBackups: Record<string, string>;
|
||||
export let limit: number;
|
||||
export let offset: number;
|
||||
export let view: 'grid' | 'table';
|
||||
export let search: string | null;
|
||||
export let clearSearchHref: string | null = null;
|
||||
export let getDatabaseUrl: (db: Models.Database, firstTableId?: string | null) => string | null = (db, t) => db ? dbHref(db.$id, t ?? null) : null;
|
||||
let {
|
||||
databases,
|
||||
tables,
|
||||
policies,
|
||||
lastBackups,
|
||||
limit,
|
||||
offset,
|
||||
view,
|
||||
search,
|
||||
getDatabaseUrl
|
||||
}: {
|
||||
databases: { total: number; databases: Models.Database[] };
|
||||
tables: Record<string, string>;
|
||||
policies: Record<string, Array<{ schedule: string }>>;
|
||||
lastBackups: Record<string, string>;
|
||||
limit: number;
|
||||
offset: number;
|
||||
view: View;
|
||||
search: string | null;
|
||||
getDatabaseUrl: (database: Models.Database, firstTableId?: string | null) => string | null;
|
||||
} = $props();
|
||||
|
||||
let showCreate = false;
|
||||
let showCreate = $state(false);
|
||||
|
||||
const clearSearchHref = page.url.pathname;
|
||||
async function onCreated(e: CustomEvent<Models.Database>) {
|
||||
showCreate = false;
|
||||
const href = getDatabaseUrl(e.detail, null);
|
||||
if (href) await goto(href);
|
||||
}
|
||||
|
||||
function dbHref(id: string, tableId?: string | null) {
|
||||
const t = tableId ? `/table-${tableId}` : '';
|
||||
return `${base}/project-${page.params.region}-${page.params.project}/databases/database-${id}${t}`;
|
||||
}
|
||||
|
||||
function getPolicyDescription(cron: string): string {
|
||||
const [minute, hour, dayOfMonth, , dayOfWeek] = cron.split(' ');
|
||||
if (dayOfMonth !== '*') return 'Monthly';
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import { Container } from '$lib/layout';
|
||||
import View from './view.svelte';
|
||||
export let data;
|
||||
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
|
||||
const createMessageUrl = (message: Models.Message) => `${base}/project-${page.params.region}-${page.params.project}/messaging/message-${message.$id}`;
|
||||
</script>
|
||||
|
||||
<View messages={data.messages} limit={data.limit} offset={data.offset} view={data.view} search={data.search} query={data.query} pageNum={data.page} />
|
||||
<Container>
|
||||
<View messages={data.messages} limit={data.limit} offset={data.offset} search={data.search} {createMessageUrl} />
|
||||
</Container>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import { Empty, EmptyFilter, EmptySearch, Id, PaginationWithLimit } from '$lib/components';
|
||||
import { hasPageQueries } from '$lib/components/filters';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import { Container, ResponsiveContainerHeader } from '$lib/layout';
|
||||
import { MessagingProviderType } from '@appwrite.io/console';
|
||||
import { MessagingProviderType, type Models } from '@appwrite.io/console';
|
||||
import CreateMessageDropdown from './createMessageDropdown.svelte';
|
||||
import FailedModal from './failedModal.svelte';
|
||||
import MessageStatusPill from './messageStatusPill.svelte';
|
||||
@@ -25,21 +24,28 @@
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { stopPolling, pollMessagesStatus } from './helper';
|
||||
|
||||
export let messages: { total: number; messages: any[] };
|
||||
export let limit: number;
|
||||
export let offset: number;
|
||||
export let view: 'grid' | 'table';
|
||||
export let search: string | null;
|
||||
export let query: string | null;
|
||||
export let pageNum: number;
|
||||
export let clearSearchHref: string | null = null;
|
||||
export let getMessageUrl: (m: any) => string = (m) => `${base}/project-${region}-${project}/messaging/message-${m.$id}`;
|
||||
let {
|
||||
messages,
|
||||
limit,
|
||||
offset,
|
||||
search,
|
||||
createMessageUrl
|
||||
}: {
|
||||
messages: { total: number; messages: Models.Message[] };
|
||||
limit: number;
|
||||
offset: number;
|
||||
search: string | null;
|
||||
createMessageUrl: (message: Models.Message) => string;
|
||||
} = $props();
|
||||
|
||||
let selected: string[] = [];
|
||||
let showDelete = false;
|
||||
let deleting = false;
|
||||
let showFailed = false;
|
||||
let errors: string[] = [];
|
||||
let selected = $state<string[]>([]);
|
||||
let showDelete = $state(false);
|
||||
let deleting = $state(false);
|
||||
let showFailed = $state(false);
|
||||
let errors = $state<string[]>([]);
|
||||
|
||||
const region = page.params.region;
|
||||
const project = page.params.project;
|
||||
|
||||
const columns = writable<Column[]>([
|
||||
{ id: '$id', title: 'Message ID', type: 'string', width: 200 },
|
||||
@@ -50,9 +56,6 @@
|
||||
{ id: 'deliveredAt', title: 'Delivered at', type: 'datetime', width: { min: 120 } }
|
||||
]);
|
||||
|
||||
const region = page.params.region;
|
||||
const project = page.params.project;
|
||||
|
||||
async function handleDelete() {
|
||||
showDelete = false;
|
||||
const promises = selected.map((id) => sdk.forProject(region, project).messaging.delete({ messageId: id }));
|
||||
@@ -77,19 +80,17 @@
|
||||
onDestroy(stopPolling);
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<ResponsiveContainerHeader
|
||||
{columns}
|
||||
bind:view
|
||||
hideView
|
||||
hasFilters
|
||||
hasSearch
|
||||
analyticsSource="messaging_messages"
|
||||
searchPlaceholder="Search by description, type, status, or ID">
|
||||
{#if $canWriteMessages}
|
||||
<CreateMessageDropdown />
|
||||
{/if}
|
||||
</ResponsiveContainerHeader>
|
||||
<ResponsiveContainerHeader
|
||||
{columns}
|
||||
hideView
|
||||
hasFilters
|
||||
hasSearch
|
||||
analyticsSource="messaging_messages"
|
||||
searchPlaceholder="Search by description, type, status, or ID">
|
||||
{#if $canWriteMessages}
|
||||
<CreateMessageDropdown />
|
||||
{/if}
|
||||
</ResponsiveContainerHeader>
|
||||
|
||||
{#if messages.total}
|
||||
<Table.Root columns={$columns} allowSelection={$canWriteMessages} let:root bind:selectedRows={selected}>
|
||||
@@ -99,7 +100,7 @@
|
||||
{/each}
|
||||
</svelte:fragment>
|
||||
{#each messages.messages as message (message.$id)}
|
||||
<Table.Row.Link {root} id={message.$id} href={getMessageUrl(message)}>
|
||||
<Table.Row.Link {root} id={message.$id} href={createMessageUrl(message)}>
|
||||
{#each $columns as column (column.id)}
|
||||
<Table.Cell column={column.id} {root}>
|
||||
{#if column.id === '$id'}
|
||||
@@ -156,7 +157,7 @@
|
||||
</div>
|
||||
<div class="u-flex u-gap-16">
|
||||
<Button external href="https://appwrite.io/docs/products/messaging/messages" text>Documentation</Button>
|
||||
<Button secondary href={clearSearchHref ?? `${base}/project-${region}-${project}/messaging`}>Clear search</Button>
|
||||
<Button secondary href={page.url.pathname}>Clear search</Button>
|
||||
</div>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
@@ -171,7 +172,6 @@
|
||||
</svelte:fragment>
|
||||
</Empty>
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
<FailedModal bind:show={showFailed} {errors} />
|
||||
<Confirm title="Delete messages" bind:open={showDelete} onSubmit={handleDelete} disabled={deleting}>
|
||||
|
||||
@@ -3,15 +3,26 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { Container } from '$lib/layout';
|
||||
import View from './view.svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
export let data;
|
||||
|
||||
const createBucketUrl = (bucket: Models.Bucket) => {
|
||||
return `${base}/project-${page.params.region}-${page.params.project}/storage/bucket-${bucket.$id}`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<View
|
||||
buckets={data.buckets}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
view={data.view}
|
||||
search={data.search}
|
||||
/>
|
||||
<Container>
|
||||
<View
|
||||
buckets={data.buckets}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
view={data.view}
|
||||
search={data.search}
|
||||
{createBucketUrl}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
+17
-1
@@ -1,6 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { Container } from '$lib/layout';
|
||||
import View from './view.svelte';
|
||||
export let data;
|
||||
|
||||
const createFileUrl = (file: Models.File) => {
|
||||
return `${base}/project-${page.params.region}-${page.params.project}/storage/bucket-${page.params.bucket}/file-${file.$id}`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<View files={data.files} limit={data.limit} offset={data.offset} search={data.search} />
|
||||
<Container>
|
||||
<View
|
||||
files={data.files}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
search={data.search}
|
||||
{createFileUrl}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
+142
-93
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { goto, invalidate } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { Avatar, Empty, EmptySearch, PaginationWithLimit, SearchQuery } from '$lib/components';
|
||||
@@ -8,7 +7,6 @@
|
||||
import { Badge } from '@appwrite.io/pink-svelte';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { calculateSize } from '$lib/helpers/sizeConvertion';
|
||||
import { Container } from '$lib/layout';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { uploader } from '$lib/stores/uploader';
|
||||
@@ -19,15 +17,25 @@
|
||||
import DualTimeView from '$lib/components/dualTimeView.svelte';
|
||||
import { IconDotsHorizontal, IconPencil, IconPlus, IconTrash } from '@appwrite.io/pink-icons-svelte';
|
||||
|
||||
export let files: { total: number; files: Models.File[] };
|
||||
export let limit: number;
|
||||
export let offset: number;
|
||||
export let search: string | null;
|
||||
let {
|
||||
files,
|
||||
limit,
|
||||
offset,
|
||||
search,
|
||||
createFileUrl
|
||||
}: {
|
||||
files: { total: number; files: Models.File[] };
|
||||
limit: number;
|
||||
offset: number;
|
||||
search: string | null;
|
||||
createFileUrl?: (file: Models.File) => string;
|
||||
} = $props();
|
||||
|
||||
let showDelete = false;
|
||||
let selectedFile: Models.File = null;
|
||||
let showDelete = $state(false);
|
||||
let selectedFile = $state<Models.File | null>(null);
|
||||
|
||||
const bucketId = page.params.bucket;
|
||||
const clearSearchHref = page.url.pathname;
|
||||
|
||||
function getPreview(fileId: string) {
|
||||
return (
|
||||
@@ -56,113 +64,154 @@
|
||||
}
|
||||
}
|
||||
|
||||
let isUploading = false;
|
||||
const beforeunload = (event: BeforeUnloadEvent) => {
|
||||
const message = 'An upload is in progress. Are you sure you want to leave?';
|
||||
if (isUploading) {
|
||||
function beforeunload(event: BeforeUnloadEvent) {
|
||||
if (uploader.uploading) {
|
||||
event.preventDefault();
|
||||
event.returnValue = message;
|
||||
return message;
|
||||
event.returnValue = '';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
return uploader.subscribe(() => {
|
||||
isUploading = $uploader.files.some((file) => file.status !== 'success' && file.progress < 100 && file.status !== 'failed');
|
||||
});
|
||||
});
|
||||
onMount(() => uploader.setBucket(bucketId));
|
||||
</script>
|
||||
|
||||
<svelte:window on:beforeunload={beforeunload} />
|
||||
|
||||
<Container>
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<SearchQuery placeholder="Search files" />
|
||||
</Layout.Stack>
|
||||
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<Button href={`${base}/project-${page.params.region}-${page.params.project}/storage/bucket-${page.params.bucket}/create`} event="create_file" size="s">
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Create file
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<SearchQuery placeholder="Search files" />
|
||||
</Layout.Stack>
|
||||
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<Button secondary href="create" event="create_file" size="s">
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Upload
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
|
||||
{#if files.total}
|
||||
<Table.Root let:root columns={[{ id: 'filename' }, { id: 'type', width: { min: 140 } }, { id: 'size', width: { min: 100 } }, { id: 'created', width: { min: 120 } }, { id: 'actions', width: 40 }]}>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
<Table.Header.Cell column="filename" {root}>Filename</Table.Header.Cell>
|
||||
<Table.Header.Cell column="type" {root}>Type</Table.Header.Cell>
|
||||
<Table.Header.Cell column="size" {root}>Size</Table.Header.Cell>
|
||||
<Table.Header.Cell column="created" {root}>Created</Table.Header.Cell>
|
||||
<Table.Header.Cell column="actions" {root} />
|
||||
</svelte:fragment>
|
||||
{#each files.files as file (file.$id)}
|
||||
{#if $uploader.files.find(({ $id }) => $id === file.$id)}
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell column="filename" {root}>
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<span class="avatar is-size-small is-color-empty"></span>
|
||||
<span class="text u-trim">{file.name}</span>
|
||||
<div><Badge variant="secondary" type="warning" content="Pending" /></div>
|
||||
</Layout.Stack>
|
||||
</Table.Cell>
|
||||
<Table.Cell column="type" {root}>{file.mimeType}</Table.Cell>
|
||||
<Table.Cell column="size" {root}>{calculateSize(file.sizeOriginal)}</Table.Cell>
|
||||
<Table.Cell column="created" {root}><DualTimeView time={file.$createdAt} /></Table.Cell>
|
||||
<Table.Cell column="actions" {root}>
|
||||
<div class="u-flex u-main-center">
|
||||
<button class="button is-only-icon is-text" aria-label="Delete item" on:click|preventDefault={() => deleteFile(file)}>
|
||||
<span class="icon-trash" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
{:else}
|
||||
{@const href = `${base}/project-${page.params.region}-${page.params.project}/storage/bucket-${bucketId}/file-${file.$id}`}
|
||||
{#if files.total}
|
||||
<Table.Root columns={7} let:root>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
<Table.Header.Cell {root}>Name</Table.Header.Cell>
|
||||
<Table.Header.Cell {root}>Type</Table.Header.Cell>
|
||||
<Table.Header.Cell {root}>Size</Table.Header.Cell>
|
||||
<Table.Header.Cell {root}>Created</Table.Header.Cell>
|
||||
<Table.Header.Cell {root}>Updated</Table.Header.Cell>
|
||||
<Table.Header.Cell {root}></Table.Header.Cell>
|
||||
</svelte:fragment>
|
||||
{#each files.files as file}
|
||||
{#if uploader.uploading && file.$id === uploader.file?.$id}
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell column="filename" {root}>
|
||||
<div class="u-flex u-gap-12 u-cross-center">
|
||||
<Avatar size="s" src={getPreview(file.$id)} alt={file.name} />
|
||||
<span class="text u-trim">{file.name}</span>
|
||||
</div>
|
||||
</Table.Cell>
|
||||
<Table.Cell column="mimeType" {root}>
|
||||
<Badge size="s" variant="secondary">{file.mimeType}</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell column="sizeOriginal" {root}>
|
||||
{calculateSize(file.sizeOriginal)}
|
||||
</Table.Cell>
|
||||
<Table.Cell column="$createdAt" {root}>
|
||||
<DualTimeView time={file.$createdAt} />
|
||||
</Table.Cell>
|
||||
<Table.Cell column="$updatedAt" {root}>
|
||||
<DualTimeView time={file.$updatedAt} />
|
||||
</Table.Cell>
|
||||
<Table.Cell {root}>
|
||||
<!-- uploading state -->
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
{:else}
|
||||
{@const href = createFileUrl ? createFileUrl(file) : null}
|
||||
{#if href}
|
||||
<Table.Row.Link {href} {root}>
|
||||
<Table.Cell column="filename" {root}>
|
||||
<div class="u-flex u-gap-12 u-cross-center">
|
||||
<Avatar size="xs" src={getPreview(file.$id)} alt={file.name} />
|
||||
<Avatar size="s" src={getPreview(file.$id)} alt={file.name} />
|
||||
<span class="text u-trim">{file.name}</span>
|
||||
</div>
|
||||
</Table.Cell>
|
||||
<Table.Cell column="type" {root}>{file.mimeType}</Table.Cell>
|
||||
<Table.Cell column="size" {root}>{calculateSize(file.sizeOriginal)}</Table.Cell>
|
||||
<Table.Cell column="created" {root}><DualTimeView time={file.$createdAt} /></Table.Cell>
|
||||
<Table.Cell column="actions" {root}>
|
||||
<Popover let:toggle placement="bottom-start" padding="none">
|
||||
<Button text icon ariaLabel="more options" on:click={(e) => { e.stopPropagation(); e.preventDefault(); toggle(); }}>
|
||||
<Table.Cell column="mimeType" {root}>
|
||||
<Badge size="s" variant="secondary">{file.mimeType}</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell column="sizeOriginal" {root}>
|
||||
{calculateSize(file.sizeOriginal)}
|
||||
</Table.Cell>
|
||||
<Table.Cell column="$createdAt" {root}>
|
||||
<DualTimeView time={file.$createdAt} />
|
||||
</Table.Cell>
|
||||
<Table.Cell column="$updatedAt" {root}>
|
||||
<DualTimeView time={file.$updatedAt} />
|
||||
</Table.Cell>
|
||||
<Table.Cell {root}>
|
||||
<Popover>
|
||||
<Button icon size="s" variant="ghost">
|
||||
<Icon icon={IconDotsHorizontal} size="s" />
|
||||
</Button>
|
||||
<ActionMenu.Root slot="tooltip">
|
||||
<ActionMenu.Item.Anchor {href} leadingIcon={IconPencil}>Update</ActionMenu.Item.Anchor>
|
||||
<ActionMenu.Item.Button leadingIcon={IconTrash} on:click={(e) => { e.stopPropagation(); e.preventDefault(); selectedFile = file; showDelete = true; }}>Delete</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
<svelte:fragment slot="content" let:close>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button icon={IconPencil} on:click={() => { close(); goto(href); }}>
|
||||
Edit
|
||||
</ActionMenu.Item.Button>
|
||||
<ActionMenu.Item.Button icon={IconTrash} on:click={() => { close(); selectedFile = file; showDelete = true; }}>
|
||||
Delete
|
||||
</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
</Table.Cell>
|
||||
</Table.Row.Link>
|
||||
{:else}
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell column="filename" {root}>
|
||||
<div class="u-flex u-gap-12 u-cross-center">
|
||||
<Avatar size="s" src={getPreview(file.$id)} alt={file.name} />
|
||||
<span class="text u-trim">{file.name}</span>
|
||||
</div>
|
||||
</Table.Cell>
|
||||
<Table.Cell column="mimeType" {root}>
|
||||
<Badge size="s" variant="secondary">{file.mimeType}</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell column="sizeOriginal" {root}>
|
||||
{calculateSize(file.sizeOriginal)}
|
||||
</Table.Cell>
|
||||
<Table.Cell column="$createdAt" {root}>
|
||||
<DualTimeView time={file.$createdAt} />
|
||||
</Table.Cell>
|
||||
<Table.Cell column="$updatedAt" {root}>
|
||||
<DualTimeView time={file.$updatedAt} />
|
||||
</Table.Cell>
|
||||
<Table.Cell {root}>
|
||||
<Popover>
|
||||
<Button icon size="s" variant="ghost">
|
||||
<Icon icon={IconDotsHorizontal} size="s" />
|
||||
</Button>
|
||||
<svelte:fragment slot="content" let:close>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button icon={IconTrash} on:click={() => { close(); selectedFile = file; showDelete = true; }}>
|
||||
Delete
|
||||
</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
{/if}
|
||||
{/each}
|
||||
</Table.Root>
|
||||
{/if}
|
||||
{/each}
|
||||
</Table.Root>
|
||||
|
||||
<PaginationWithLimit name="Files" {limit} {offset} total={files.total} />
|
||||
{:else if search}
|
||||
<EmptySearch>
|
||||
<div class="u-text-center">
|
||||
<b>Sorry, we couldn't find '{search}'</b>
|
||||
<p>There are no files that match your search.</p>
|
||||
</div>
|
||||
<div class="u-flex u-gap-16">
|
||||
<Button external href="https://appwrite.io/docs/products/storage/upload-download" text>Documentation</Button>
|
||||
<Button secondary href={`${base}/project-${page.params.region}-${page.params.project}/storage/bucket-${page.params.bucket}`}>Clear Search</Button>
|
||||
</div>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Empty single target="file" href="https://appwrite.io/docs/products/storage/upload-download" on:click={() => goto(`${base}/project-${page.params.region}-${page.params.project}/storage/bucket-${page.params.bucket}/create`)} />
|
||||
{/if}
|
||||
</Container>
|
||||
<PaginationWithLimit name="Files" {limit} {offset} total={files.total} />
|
||||
{:else if search}
|
||||
<EmptySearch target="files" hidePagination>
|
||||
<Button size="s" secondary href={clearSearchHref}>Clear Search</Button>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Empty single target="file" href="https://appwrite.io/docs/products/storage/upload-download" on:click={() => goto("create")} />
|
||||
{/if}
|
||||
|
||||
{#if selectedFile}
|
||||
<DeleteFile file={selectedFile} bind:showDelete on:deleted={fileDeleted} />
|
||||
{/if}
|
||||
{/if}
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import { Empty, PaginationWithLimit, SearchQuery, Id, CardContainer, GridItem1 } from '$lib/components';
|
||||
import { canWriteBuckets } from '$lib/stores/roles';
|
||||
@@ -14,19 +13,27 @@
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { showCreateBucket } from './+page.svelte';
|
||||
|
||||
export let buckets: { total: number; buckets: Models.Bucket[] };
|
||||
export let limit: number;
|
||||
export let offset: number;
|
||||
export let view: 'grid' | 'table';
|
||||
export let search: string | null;
|
||||
let {
|
||||
buckets,
|
||||
limit,
|
||||
offset,
|
||||
view,
|
||||
search,
|
||||
createBucketUrl
|
||||
}: {
|
||||
buckets: { total: number; buckets: Models.Bucket[] };
|
||||
limit: number;
|
||||
offset: number;
|
||||
view: 'grid' | 'table';
|
||||
search: string | null;
|
||||
createBucketUrl: (bucket: Models.Bucket) => string;
|
||||
} = $props();
|
||||
|
||||
function bucketHref(id: string) {
|
||||
return `${base}/project-${page.params.region}-${page.params.project}/storage/bucket-${id}`;
|
||||
}
|
||||
const clearSearchHref = page.url.pathname;
|
||||
|
||||
async function bucketCreated(event: CustomEvent<Models.Bucket>) {
|
||||
showCreateBucket.set(false);
|
||||
await goto(bucketHref(event.detail.$id));
|
||||
await goto(createBucketUrl(event.detail));
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -49,7 +56,7 @@
|
||||
{#if view === 'grid'}
|
||||
<CardContainer disableEmpty={!$canWriteBuckets} total={buckets.total} {offset} event="bucket" service="buckets" on:click={() => ($showCreateBucket = true)}>
|
||||
{#each buckets.buckets as bucket}
|
||||
<GridItem1 href={bucketHref(bucket.$id)}>
|
||||
<GridItem1 href={createBucketUrl(bucket)}>
|
||||
<svelte:fragment slot="title">{bucket.name}</svelte:fragment>
|
||||
<svelte:fragment slot="status">
|
||||
{#if !bucket.enabled}
|
||||
@@ -77,7 +84,7 @@
|
||||
{/each}
|
||||
</svelte:fragment>
|
||||
{#each buckets.buckets as bucket (bucket.$id)}
|
||||
<PinkTable.Row.Link {root} href={bucketHref(bucket.$id)}>
|
||||
<PinkTable.Row.Link {root} href={createBucketUrl(bucket)}>
|
||||
{#each $columns as column}
|
||||
<PinkTable.Cell column={column.id} {root}>
|
||||
{#if column.id === '$id'}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
<script lang="ts">
|
||||
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';
|
||||
export let data;
|
||||
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
const createUserUrl = (user: Models.User<{}>) => `${base}/embed/project-${page.params.region}-${page.params.project}/auth/user-${user.$id}`;
|
||||
</script>
|
||||
|
||||
<View
|
||||
users={data.users}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
pageNum={data.page}
|
||||
search={data.search}
|
||||
/>
|
||||
<Layout.Stack>
|
||||
<View
|
||||
users={data.users}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
search={data.search}
|
||||
{createUserUrl}
|
||||
/>
|
||||
</Layout.Stack>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { Layout } from '@appwrite.io/pink-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>
|
||||
|
||||
<Container>
|
||||
<Layout.Stack>
|
||||
<UpdateUsersLimit />
|
||||
<UpdateSessionLength />
|
||||
<UpdateSessionsLimit />
|
||||
@@ -21,5 +21,5 @@
|
||||
<UpdateSessionAlerts />
|
||||
<UpdateSessionInvalidation />
|
||||
<UpdateMembershipPrivacy />
|
||||
</Container>
|
||||
</Layout.Stack>
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { Layout } from '@appwrite.io/pink-svelte';
|
||||
import View from '$routes/(console)/project-[region]-[project]/auth/settings/view.svelte';
|
||||
</script>
|
||||
|
||||
<View />
|
||||
<Layout.Stack>
|
||||
<View />
|
||||
</Layout.Stack>
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
<script lang="ts">
|
||||
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';
|
||||
export let data;
|
||||
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>
|
||||
|
||||
<View
|
||||
teams={data.teams}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
pageNum={data.page}
|
||||
search={data.search}
|
||||
/>
|
||||
<Layout.Stack>
|
||||
<View
|
||||
teams={data.teams}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
search={data.search}
|
||||
{createTeamUrl}
|
||||
/>
|
||||
</Layout.Stack>
|
||||
|
||||
+5
-2
@@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { Layout } from '@appwrite.io/pink-svelte';
|
||||
import View from '$routes/(console)/project-[region]-[project]/auth/templates/view.svelte';
|
||||
export let data;
|
||||
let { data } = $props();
|
||||
</script>
|
||||
|
||||
<View project={data.project} />
|
||||
<Layout.Stack>
|
||||
<View project={data.project} />
|
||||
</Layout.Stack>
|
||||
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { Layout } from '@appwrite.io/pink-svelte';
|
||||
import View from '$routes/(console)/project-[region]-[project]/auth/user-[user]/view.svelte';
|
||||
</script>
|
||||
|
||||
<View />
|
||||
<Layout.Stack>
|
||||
<View />
|
||||
</Layout.Stack>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load: LayoutLoad = async ({ parent }) => {
|
||||
const { project } = await parent();
|
||||
return { project };
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
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]/databases/view.svelte';
|
||||
let { data } = $props();
|
||||
|
||||
const getDatabaseUrl = (database: Models.Database, firstTableId?: string | null) => {
|
||||
const tableSegment = firstTableId ? `/table-${firstTableId}` : '';
|
||||
return `${base}/embed/project-${page.params.region}-${page.params.project}/databases/database-${database.$id}${tableSegment}`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<Layout.Stack>
|
||||
<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}
|
||||
{getDatabaseUrl}
|
||||
/>
|
||||
</Layout.Stack>
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ parent, url }) => {
|
||||
const { project } = await parent();
|
||||
|
||||
// Import the console page loader to reuse the same logic
|
||||
const consoleLoader = await import('$routes/(console)/project-[region]-[project]/databases/+page.ts');
|
||||
|
||||
// Call the console loader with the same parameters
|
||||
return await consoleLoader.load({ parent, url });
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load: LayoutLoad = async ({ parent }) => {
|
||||
const { project } = await parent();
|
||||
return { project };
|
||||
};
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
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';
|
||||
let { data } = $props();
|
||||
|
||||
const createTableUrl = (table) => {
|
||||
return `${base}/embed/project-${page.params.region}-${page.params.project}/databases/database-${page.params.database}/table-${table.$id}`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<Layout.Stack>
|
||||
<View
|
||||
tables={data.tables}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
view={data.view}
|
||||
search={data.search}
|
||||
{createTableUrl}
|
||||
/>
|
||||
</Layout.Stack>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ parent, url, params }) => {
|
||||
const { project } = await parent();
|
||||
|
||||
// Import the console page loader to reuse the same logic
|
||||
const consoleLoader = await import('$routes/(console)/project-[region]-[project]/databases/database-[database]/+page.ts');
|
||||
|
||||
// Call the console loader with the same parameters
|
||||
return await consoleLoader.load({ parent, url, params });
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load: LayoutLoad = async ({ parent }) => {
|
||||
const { project } = await parent();
|
||||
return { project };
|
||||
};
|
||||
+9
@@ -0,0 +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';
|
||||
let { data } = $props();
|
||||
</script>
|
||||
|
||||
<Layout.Stack>
|
||||
<TablePage {data} />
|
||||
</Layout.Stack>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ parent, url, params }) => {
|
||||
const { project } = await parent();
|
||||
|
||||
// Import the console page loader to reuse the same logic
|
||||
const consoleLoader = await import('$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.ts');
|
||||
|
||||
// Call the console loader with the same parameters
|
||||
return await consoleLoader.load({ parent, url, params });
|
||||
};
|
||||
@@ -1,21 +1,20 @@
|
||||
<script lang="ts">
|
||||
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]/messaging/view.svelte';
|
||||
export let data;
|
||||
let { data } = $props();
|
||||
|
||||
const clearSearchHref = `${base}/embed/project-${page.params.region}-${page.params.project}/messaging`;
|
||||
const getMessageUrl = (m: any) => `${base}/embed/project-${page.params.region}-${page.params.project}/messaging/message-${m.$id}`;
|
||||
const createMessageUrl = (message) => `${base}/embed/project-${page.params.region}-${page.params.project}/messaging/message-${message.$id}`;
|
||||
</script>
|
||||
|
||||
<View
|
||||
messages={data.messages}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
view={data.view}
|
||||
search={data.search}
|
||||
query={data.query}
|
||||
pageNum={data.page}
|
||||
{clearSearchHref}
|
||||
{getMessageUrl}
|
||||
/>
|
||||
<Layout.Stack>
|
||||
<View
|
||||
messages={data.messages}
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
search={data.search}
|
||||
{createMessageUrl}
|
||||
/>
|
||||
</Layout.Stack>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load: LayoutLoad = async ({ parent }) => {
|
||||
const { project } = await parent();
|
||||
return { project };
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
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]/storage/view.svelte';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
const createBucketUrl = (bucket: Models.Bucket) => {
|
||||
return `${base}/embed/project-${page.params.region}-${page.params.project}/storage/bucket-${bucket.$id}`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<Layout.Stack>
|
||||
<View
|
||||
buckets={data?.buckets || { total: 0, buckets: [] }}
|
||||
limit={data?.limit || 25}
|
||||
offset={data?.offset || 0}
|
||||
view={data?.view || 'grid'}
|
||||
search={data?.search || null}
|
||||
{createBucketUrl}
|
||||
/>
|
||||
</Layout.Stack>
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ parent, url, params }) => {
|
||||
const { project } = await parent();
|
||||
|
||||
// Import the console page loader to reuse the same logic
|
||||
const consoleLoader = await import('$routes/(console)/project-[region]-[project]/storage/+page.ts');
|
||||
|
||||
// Call the console loader with the same parameters
|
||||
return await consoleLoader.load({ parent, url, params });
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load: LayoutLoad = async ({ parent }) => {
|
||||
const { project } = await parent();
|
||||
return { project };
|
||||
};
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<script lang="ts">
|
||||
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]/storage/bucket-[bucket]/view.svelte';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
const createFileUrl = (file: Models.File) => {
|
||||
return `${base}/embed/project-${page.params.region}-${page.params.project}/storage/bucket-${page.params.bucket}/file-${file.$id}`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<Layout.Stack>
|
||||
<View
|
||||
files={data?.files || { total: 0, files: [] }}
|
||||
limit={data?.limit || 25}
|
||||
offset={data?.offset || 0}
|
||||
search={data?.search || null}
|
||||
{createFileUrl}
|
||||
/>
|
||||
</Layout.Stack>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ parent, url, params }) => {
|
||||
const { project } = await parent();
|
||||
|
||||
// Import the console page loader to reuse the same logic
|
||||
const consoleLoader = await import('$routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.ts');
|
||||
|
||||
// Call the console loader with the same parameters
|
||||
return await consoleLoader.load({ parent, url, params });
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load: LayoutLoad = async ({ parent }) => {
|
||||
const { project } = await parent();
|
||||
return { project };
|
||||
};
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<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} />
|
||||
</Layout.Stack>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ parent, url, params }) => {
|
||||
const { project } = await parent();
|
||||
|
||||
// Import the console page loader to reuse the same logic
|
||||
const consoleLoader = await import('$routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/+page.ts');
|
||||
|
||||
// Call the console loader with the same parameters
|
||||
return await consoleLoader.load({ parent, url, params });
|
||||
};
|
||||
@@ -4,7 +4,12 @@ body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
[data-loading='true'] .page-loader {
|
||||
[data-embed] {
|
||||
background: none !important;
|
||||
background-color: none !important;
|
||||
}
|
||||
|
||||
[data-loading='true']:not([data-embed]) .page-loader {
|
||||
pointer-events: initial;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
|
||||
Reference in New Issue
Block a user