diff --git a/src/lib/components/avatar.svelte b/src/lib/components/avatar.svelte
index 0ff36651a..e341375aa 100644
--- a/src/lib/components/avatar.svelte
+++ b/src/lib/components/avatar.svelte
@@ -1,6 +1,12 @@
-{#if filteredModalAlerts.length > 0 && currentModalAlert}
+{#if filteredModalAlerts.length > 0 && currentModalAlert && !page.url.pathname.includes('console/onboarding')}
{@const shouldShowUpgrade = showUpgrade()}
@@ -164,8 +208,8 @@
{/if}
{/if}
@@ -377,6 +442,22 @@
border: hsl(var(--color-neutral-80)) solid 1px;
}
+ :global(.main-alert-wrapper .only-primary-cta) {
+ width: 100%;
+ text-align: center;
+ justify-content: center;
+ }
+
+ .showcase-image.u-only-light {
+ border-radius: 8px;
+ border: 0.795px solid var(--border-neutral-strong, #d8d8db);
+ }
+
+ .showcase-image.u-only-dark {
+ border-radius: 8px;
+ border: 0.795px solid var(--border-neutral-strong, #414146);
+ }
+
.u-gap-10 {
gap: 0.625rem;
}
diff --git a/src/lib/components/box.svelte b/src/lib/components/box.svelte
index 448f93c85..d129900a0 100644
--- a/src/lib/components/box.svelte
+++ b/src/lib/components/box.svelte
@@ -1,10 +1,9 @@
diff --git a/src/lib/components/breadcrumbs.svelte b/src/lib/components/breadcrumbs.svelte
index 6bc8adf40..7d9329f3c 100644
--- a/src/lib/components/breadcrumbs.svelte
+++ b/src/lib/components/breadcrumbs.svelte
@@ -19,6 +19,7 @@
name: string;
$id: string;
isSelected: boolean;
+ region: string;
};
type Organization = {
name: string;
diff --git a/src/lib/components/card.svelte b/src/lib/components/card.svelte
index 28af1975c..fd94436ab 100644
--- a/src/lib/components/card.svelte
+++ b/src/lib/components/card.svelte
@@ -1,7 +1,16 @@
+
+
diff --git a/src/lib/components/labelCard.svelte b/src/lib/components/labelCard.svelte
index ffcd8474c..8f2cc80c4 100644
--- a/src/lib/components/labelCard.svelte
+++ b/src/lib/components/labelCard.svelte
@@ -1,9 +1,24 @@
{#if !hidePages}
-
+
{:else}
& {
state?: 'closed' | 'open' | 'icons';
- project: { $id: string } | undefined;
+ project: NavbarProject | undefined;
avatar: string;
progressCard?: {
title: string;
diff --git a/src/lib/components/tab.svelte b/src/lib/components/tab.svelte
index 48946ea47..8c8d2041e 100644
--- a/src/lib/components/tab.svelte
+++ b/src/lib/components/tab.svelte
@@ -5,13 +5,12 @@
import { getElementDir } from '$lib/helpers/style';
import { waitUntil } from '$lib/helpers/waitUntil';
import { Tabs } from '@appwrite.io/pink-svelte';
- import type { Variant } from '@appwrite.io/pink-svelte/dist/tabs/types';
export let selected = false;
export let href: string = null;
export let event: string = null;
export let noscroll = false;
- export let root: { variant: Variant; stretch: boolean } = {
+ export let root: { variant: 'primary' | 'secondary'; stretch: boolean } = {
variant: 'primary',
stretch: false
};
diff --git a/src/lib/elements/forms/inputDateTime.svelte b/src/lib/elements/forms/inputDateTime.svelte
index 75dcaa27f..360b0f4c7 100644
--- a/src/lib/elements/forms/inputDateTime.svelte
+++ b/src/lib/elements/forms/inputDateTime.svelte
@@ -3,7 +3,7 @@
import { Input, Layout, Selector } from '@appwrite.io/pink-svelte';
export let id: string;
- export let label: string;
+ export let label: string = '';
export let value: string;
export let required = false;
export let nullable = false;
@@ -48,7 +48,7 @@
{value}
{step}
helper={error}
- on:change={(event) => (value = event.target.value)}
+ on:change={(event) => (value = (event.target as HTMLInputElement).value)}
autocomplete={autocomplete ? 'on' : 'off'}>
{#if nullable}
>(
): value is T[keyof T] {
return Object.values(enumType).includes(value);
}
+
+export type TableRootProp = {
+ allowSelection: boolean;
+ selectedRows: string[];
+ selectedAll: boolean;
+ selectedNone: boolean;
+ selectedSome: boolean;
+ columns: Record;
+ toggle: (id: string) => void;
+ toggleAll: () => void;
+ addAvailableId: (id: string) => void;
+ removeAvailableId: (id: string) => void;
+};
diff --git a/src/lib/images/backups/promo/backups-dark.png b/src/lib/images/backups/promo/backups-dark.png
deleted file mode 100644
index 6b31eab88..000000000
Binary files a/src/lib/images/backups/promo/backups-dark.png and /dev/null differ
diff --git a/src/lib/images/backups/promo/backups-light.png b/src/lib/images/backups/promo/backups-light.png
deleted file mode 100644
index aa675d86b..000000000
Binary files a/src/lib/images/backups/promo/backups-light.png and /dev/null differ
diff --git a/src/lib/images/promo-init3.png b/src/lib/images/promo-init3.png
new file mode 100644
index 000000000..842fa51f4
Binary files /dev/null and b/src/lib/images/promo-init3.png differ
diff --git a/src/lib/layout/activity.svelte b/src/lib/layout/activity.svelte
index 792bea865..f78f3bbe1 100644
--- a/src/lib/layout/activity.svelte
+++ b/src/lib/layout/activity.svelte
@@ -5,13 +5,13 @@
import type { Models } from '@appwrite.io/console';
import { Layout, Table, Card, Empty } from '@appwrite.io/pink-svelte';
import Button from '$lib/elements/forms/button.svelte';
- import type { Column } from '@appwrite.io/pink-svelte/dist/table';
+ import type { PinkColumn } from '$lib/helpers/types';
export let logs: Models.LogList;
export let offset = 0;
export let limit = 0;
- const columns: Column[] = [
+ const columns: PinkColumn[] = [
{ id: 'user' },
{ id: 'event' },
{ id: 'location' },
diff --git a/src/lib/stores/bottom-alerts.ts b/src/lib/stores/bottom-alerts.ts
index 1b681dcc8..aca0e067b 100644
--- a/src/lib/stores/bottom-alerts.ts
+++ b/src/lib/stores/bottom-alerts.ts
@@ -5,10 +5,28 @@ import type { Models } from '@appwrite.io/console';
type BottomModalAlertAction = {
text: string;
+ hideOnClick?: boolean;
link: (ctx: { organization: Organization; project: Models.Project }) => string;
external?: boolean;
};
+/**
+ * Special layout settings for mobile when exactly one alert is shown.
+ *
+ * Applied only if `enabled` is `true` and the number of visible alerts is exactly 1.
+ *
+ * Useful when you want to display the alert directly in the floating window,
+ * without opening a separate modal.
+ */
+export type MobileSingleAlertLayoutConfig = {
+ title: string;
+ message: string;
+ enabled: boolean;
+ isHtml?: boolean;
+ // because message is the text!
+ cta: Omit;
+};
+
export type BottomModalAlertItem = {
id: string;
title: string;
@@ -23,18 +41,36 @@ export type BottomModalAlertItem = {
importance?: number;
closed?: () => void;
- scope?: 'organization' | 'project';
+ scope: 'organization' | 'project' | 'everywhere';
notificationHideOptions?: NotificationCoolOffOptions;
};
-export const bottomModalAlerts = writable([]);
+type BottomModalAlertState = {
+ alerts: BottomModalAlertItem[];
+ mobileSingleLayout?: MobileSingleAlertLayoutConfig;
+};
+
+export const bottomModalAlertsConfig = writable({ alerts: [] });
export const hideAllModalAlerts = () => {
- bottomModalAlerts.update((all) => all.map((t) => ({ ...t, show: false })));
+ bottomModalAlertsConfig.update((state) => ({
+ ...state,
+ alerts: state.alerts.map((t) => ({ ...t, show: false }))
+ }));
+};
+
+export const setMobileSingleAlertLayout = (config: MobileSingleAlertLayoutConfig) => {
+ bottomModalAlertsConfig.update((state) => ({
+ ...state,
+ mobileSingleLayout: config
+ }));
};
export const dismissBottomModalAlert = (id: string) => {
- bottomModalAlerts.update((all) => all.filter((t) => t.id !== id));
+ bottomModalAlertsConfig.update((state) => ({
+ ...state,
+ alerts: state.alerts.filter((t) => t.id !== id)
+ }));
};
export const showBottomModalAlert = (notification: BottomModalAlertItem) => {
@@ -45,8 +81,11 @@ export const showBottomModalAlert = (notification: BottomModalAlertItem) => {
...notification
};
- bottomModalAlerts.update((all) => {
- if (all.some((t) => t.id === notification.id)) return all;
- return [...all, defaults as BottomModalAlertItem];
+ bottomModalAlertsConfig.update((state) => {
+ if (state.alerts.some((t) => t.id === notification.id)) return state;
+ return {
+ ...state,
+ alerts: [...state.alerts, defaults as BottomModalAlertItem]
+ };
});
};
diff --git a/src/routes/(console)/+layout.svelte b/src/routes/(console)/+layout.svelte
index 6890009c4..2a101bc25 100644
--- a/src/routes/(console)/+layout.svelte
+++ b/src/routes/(console)/+layout.svelte
@@ -67,6 +67,7 @@
return {
name: project?.name,
$id: project.$id,
+ region: project.region,
isSelected: data.currentProjectId === project.$id,
platformCount: project.platforms.length,
pingCount: project.pingCount
diff --git a/src/routes/(console)/+layout.ts b/src/routes/(console)/+layout.ts
index 447f41d90..f09c16ef3 100644
--- a/src/routes/(console)/+layout.ts
+++ b/src/routes/(console)/+layout.ts
@@ -53,6 +53,11 @@ export const load: LayoutLoad = async ({ params, fetch, depends, parent }) => {
projects = orgProjects.projects.length > 0 ? orgProjects.projects : [];
}
+ // set `default` if no region!
+ for (const project of projects) {
+ project.region ??= 'default';
+ }
+
return {
consoleVariables: variables,
version: data?.version ?? null,
diff --git a/src/routes/(console)/bottomAlerts.ts b/src/routes/(console)/bottomAlerts.ts
index 255f920e7..156a0dff8 100644
--- a/src/routes/(console)/bottomAlerts.ts
+++ b/src/routes/(console)/bottomAlerts.ts
@@ -1,32 +1,46 @@
-import { base } from '$app/paths';
-import BackupsDark from '$lib/images/backups/promo/backups-dark.png';
-import BackupsLight from '$lib/images/backups/promo/backups-light.png';
+import Init3Promo from '$lib/images/promo-init3.png';
-import { type BottomModalAlertItem, showBottomModalAlert } from '$lib/stores/bottom-alerts';
+import {
+ type BottomModalAlertItem,
+ setMobileSingleAlertLayout,
+ showBottomModalAlert
+} from '$lib/stores/bottom-alerts';
import { isCloud } from '$lib/system';
const listOfPromotions: BottomModalAlertItem[] = [];
if (isCloud) {
+ const title = 'Join Init 19-23 May';
+ const message =
+ 'This release will change the way you build with Appwrite forever. Register for Init and join the giveaway.';
+
+ const callToAction = {
+ external: true,
+ hideOnClick: true,
+ text: 'Claim your ticket',
+ link: () => 'https://apwr.dev/clcon'
+ };
+
listOfPromotions.push({
- id: 'modal:databaseBackups',
+ id: 'modal:init3',
src: {
- dark: BackupsDark,
- light: BackupsLight
+ dark: Init3Promo,
+ light: Init3Promo
},
- title: 'Database Backups are available now',
- message: 'Protect your data and ensure quick recovery with our new backups',
- plan: 'pro',
- scope: 'project',
+ title,
+ message,
+ plan: 'free',
importance: 8,
- cta: {
- text: 'Try now',
- link: ({ project }) => `${base}/project-${project.region}-${project.$id}/databases`
- },
- learnMore: {
- text: 'Learn more',
- link: () => 'https://appwrite.io/docs/products/databases/backups'
- }
+ scope: 'everywhere',
+ cta: callToAction
+ });
+
+ // there's only one item.
+ setMobileSingleAlertLayout({
+ title,
+ message,
+ enabled: true,
+ cta: callToAction
});
}
diff --git a/src/routes/(console)/onboarding/create-project/+page.svelte b/src/routes/(console)/onboarding/create-project/+page.svelte
index 7584dcc3e..445a9bb6f 100644
--- a/src/routes/(console)/onboarding/create-project/+page.svelte
+++ b/src/routes/(console)/onboarding/create-project/+page.svelte
@@ -2,54 +2,27 @@
import { Card, Layout, Button } from '@appwrite.io/pink-svelte';
import { isCloud } from '$lib/system';
import { sdk } from '$lib/stores/sdk';
- import { ID, Region, type Models } from '@appwrite.io/console';
+ import { ID, Region } from '@appwrite.io/console';
import Loading from './loading.svelte';
- import { BillingPlan, Dependencies } from '$lib/constants';
+ import { Dependencies } from '$lib/constants';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { goto, invalidate } from '$app/navigation';
import { base } from '$app/paths';
import { addNotification } from '$lib/stores/notifications';
- import { tierToPlan } from '$lib/stores/billing';
import CreateProject from '$lib/layout/createProject.svelte';
let isLoading = false;
let id: string;
let startAnimation = false;
let projectName = 'Appwrite project';
- let region = Region.Default;
- export let data: { regions: Models.ConsoleRegionList | null };
+ let region = Region.Fra;
+ export let data;
async function createProject() {
isLoading = true;
- let org;
- try {
- org = isCloud
- ? await sdk.forConsole.billing.createOrganization(
- ID.unique(),
- 'Personal projects',
- BillingPlan.FREE,
- null,
- null
- )
- : await sdk.forConsole.teams.create(ID.unique(), 'Personal projects');
- } catch (e) {
- isLoading = false;
- trackError(e, Submit.OrganizationCreate);
- addNotification({
- type: 'error',
- message: e.message
- });
- }
-
- trackEvent(Submit.OrganizationCreate, {
- plan: tierToPlan(BillingPlan.FREE)?.name,
- budget_cap_enabled: false,
- members_invited: 0
- });
-
- if (org) {
- const teamId = org.$id;
+ if (data.organization) {
+ const teamId = data.organization.$id;
try {
const project = await sdk.forConsole.projects.create(
id ?? ID.unique(),
diff --git a/src/routes/(console)/onboarding/create-project/+page.ts b/src/routes/(console)/onboarding/create-project/+page.ts
index e432d1cea..38fc6f4b9 100644
--- a/src/routes/(console)/onboarding/create-project/+page.ts
+++ b/src/routes/(console)/onboarding/create-project/+page.ts
@@ -1,9 +1,55 @@
import type { PageLoad } from './$types';
import { isCloud } from '$lib/system';
import { sdk } from '$lib/stores/sdk';
+import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
+import { isOrganization, tierToPlan } from '$lib/stores/billing';
+import { ID } from '@appwrite.io/console';
+import { BillingPlan } from '$lib/constants';
+import { redirect } from '@sveltejs/kit';
+import { base } from '$service-worker';
-export const load: PageLoad = async () => {
- return {
- regions: isCloud ? await sdk.forConsole.billing.listRegions() : null
- };
+export const load: PageLoad = async ({ parent }) => {
+ const { organizations } = await parent();
+ if (!organizations?.total) {
+ try {
+ if (isCloud) {
+ const org = await sdk.forConsole.billing.createOrganization(
+ ID.unique(),
+ 'Personal projects',
+ BillingPlan.FREE,
+ null,
+ null
+ );
+ trackEvent(Submit.OrganizationCreate, {
+ plan: tierToPlan(BillingPlan.FREE)?.name,
+ budget_cap_enabled: false,
+ members_invited: 0
+ });
+
+ if (isOrganization(org)) {
+ return {
+ organization: org,
+ regions: await sdk.forConsole.billing.listRegions(org.$id)
+ };
+ } else {
+ const e = new Error(org.message, {
+ cause: org
+ });
+ trackError(e, Submit.OrganizationCreate);
+ }
+ } else {
+ return {
+ organization: await sdk.forConsole.teams.create(
+ ID.unique(),
+ 'Personal projects'
+ ),
+ regions: null
+ };
+ }
+ } catch (e) {
+ trackError(e, Submit.OrganizationCreate);
+ }
+ } else {
+ redirect(303, `${base}/console/organization-${organizations.teams[0].$id}`);
+ }
};
diff --git a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte
index 615c0800d..d1300c351 100644
--- a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte
+++ b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte
@@ -53,6 +53,6 @@
-
+
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte
index e423d0082..b4b2e9915 100644
--- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte
+++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte
@@ -1,10 +1,9 @@
- Document - Appwrite
+ Data - Appwrite
-
- Metadata
-
-
-
Created: {toLocaleDateTime($doc.$createdAt)}
-
Last updated: {toLocaleDateTime($doc.$updatedAt)}
-
-
-
-
- Permissions
- A user requires appropriate permissions at either the collection level or
- document level to access a document. If no permissions are configured, no user can
- access the document
- Learn more
-
- {#if $collection.documentSecurity}
- {#if showPermissionAlert}
- (showPermissionAlert = false)}>
- Document security is enabled
-
- Users will be able to access this document if they have been granted either document or collection permissions.
-
-
-
- {/if}
- {#if permissions}
-
- {/if}
- {:else}
-
- Document security is disabled
-
- If you want to assign document permissions. Go to Collection settings and enable document
- security. Otherwise, only collection permissions will be used.
-
-
- {/if}
-
+ {#if $collection?.attributes?.length}
+ {#each $collection.attributes as attribute}
+ {@const label = attribute.key}
+
+ {label}
-
-
-
-
-
-
- Delete document
- The document will be permanently deleted, including all the data within it. This action is irreversible.
-
-
-
- {$doc.$id}
+
+
-
- Last updated: {toLocaleDateTime($doc.$updatedAt)}
-
-
-
-
-
-
-
+
+
+
+
+ {/each}
+ {/if}
-
-
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/data/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/data/+page.svelte
deleted file mode 100644
index 19aba3566..000000000
--- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/data/+page.svelte
+++ /dev/null
@@ -1,137 +0,0 @@
-
-
-
- Data - Appwrite
-
-
-
- {#if $collection?.attributes?.length}
- {#each $collection.attributes as attribute}
- {@const label = attribute.key}
-
- {label}
-
-
-
-
-
-
-
-
- {/each}
- {/if}
-
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/header.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/header.svelte
index 300d1961d..d97751b9f 100644
--- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/header.svelte
+++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/header.svelte
@@ -14,20 +14,20 @@
const tabs = [
{
href: path,
- title: 'Overview',
- event: 'overview'
- },
- {
- href: `${path}/data`,
title: 'Data',
- event: 'data',
- hasChildren: true
+ event: 'data'
},
{
href: `${path}/activity`,
title: 'Activity',
event: 'activity',
hasChildren: true
+ },
+ {
+ href: `${path}/settings`,
+ title: 'Settings',
+ event: 'settings',
+ hasChildren: true
}
];
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/settings/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/settings/+page.svelte
new file mode 100644
index 000000000..fd24eb648
--- /dev/null
+++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/document-[document]/settings/+page.svelte
@@ -0,0 +1,144 @@
+
+
+
+ Document - Appwrite
+
+
+
+
+ Metadata
+
+
+
+
Created: {toLocaleDateTime($doc.$createdAt)}
+
Last updated: {toLocaleDateTime($doc.$updatedAt)}
+
+
+
+
+ Permissions
+
+
+ A user requires appropriate permissions at either the collection level or
+ document level to access a document. If no permissions are configured, no user
+ can access the document
+ Learn more about database permissions.
+
+
+
+ {#if $collection.documentSecurity}
+ {#if showPermissionAlert}
+ (showPermissionAlert = false)}>
+ Document security is enabled
+
+ Users will be able to access this document if they have been granted either document or collection permissions.
+
+
+
+ {/if}
+ {#if permissions}
+
+ {/if}
+ {:else}
+
+ Document security is disabled
+
+ If you want to assign document permissions. Go to Collection settings and
+ enable document security. Otherwise, only collection permissions will be
+ used.
+
+
+ {/if}
+
+
+
+
+
+
+
+
+ Delete document
+
+ The document will be permanently deleted, including all the data within it. This action
+ is irreversible.
+
+
+
+
+ {$doc.$id}
+
+
+ Last updated: {toLocaleDateTime($doc.$updatedAt)}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/create/+page.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/create/+page.svelte
index ca1aa0cf5..0c43000cd 100644
--- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/create/+page.svelte
+++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/create/+page.svelte
@@ -111,6 +111,7 @@
{
return {
+ ...f,
size: f.size,
name: f.name,
removable: true,
diff --git a/src/routes/(public)/template-[template]/+page.svelte b/src/routes/(public)/template-[template]/+page.svelte
index 7462e943f..b00b007ad 100644
--- a/src/routes/(public)/template-[template]/+page.svelte
+++ b/src/routes/(public)/template-[template]/+page.svelte
@@ -95,7 +95,7 @@
id ?? ID.unique(),
projectName,
selectedOrg,
- isCloud ? (region as Region) : Region.Default
+ isCloud ? (region as Region) : Region.Fra
);
trackEvent(Submit.ProjectCreate, {
customId: !!id,