Merge remote-tracking branch 'origin/feat-plan-update' into feat-plan-update

This commit is contained in:
Darshan
2025-06-10 13:13:44 +05:30
14 changed files with 172 additions and 174 deletions
+2 -2
View File
@@ -22,11 +22,11 @@
},
"dependencies": {
"@ai-sdk/svelte": "^1.1.24",
"@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@e190a19",
"@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@a5e5564",
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "^2.0.0-RC.1",
"@appwrite.io/pink-legacy": "^1.0.3",
"@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@4e03f34",
"@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@40bae6b",
"@popperjs/core": "^2.11.8",
"@sentry/sveltekit": "^8.38.0",
"@stripe/stripe-js": "^3.5.0",
+10 -10
View File
@@ -12,8 +12,8 @@ importers:
specifier: ^1.1.24
version: 1.1.24(svelte@5.25.3)(zod@3.24.3)
'@appwrite.io/console':
specifier: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@e190a19
version: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@e190a19
specifier: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@a5e5564
version: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@a5e5564
'@appwrite.io/pink-icons':
specifier: 0.25.0
version: 0.25.0
@@ -24,8 +24,8 @@ importers:
specifier: ^1.0.3
version: 1.0.3
'@appwrite.io/pink-svelte':
specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@4e03f34
version: https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@4e03f34(svelte@5.25.3)
specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@40bae6b
version: https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@40bae6b(svelte@5.25.3)
'@popperjs/core':
specifier: ^2.11.8
version: 2.11.8
@@ -257,8 +257,8 @@ packages:
'@analytics/type-utils@0.6.2':
resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==}
'@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@e190a19':
resolution: {tarball: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@e190a19}
'@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@a5e5564':
resolution: {tarball: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@a5e5564}
version: 1.8.0
'@appwrite.io/pink-icons-svelte@2.0.0-RC.1':
@@ -281,8 +281,8 @@ packages:
'@appwrite.io/pink-legacy@1.0.3':
resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==}
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@4e03f34':
resolution: {tarball: https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@4e03f34}
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@40bae6b':
resolution: {tarball: https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@40bae6b}
version: 2.0.0-RC.2
peerDependencies:
svelte: ^4.0.0
@@ -3635,7 +3635,7 @@ snapshots:
'@analytics/type-utils@0.6.2': {}
'@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@e190a19': {}
'@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@a5e5564': {}
'@appwrite.io/pink-icons-svelte@2.0.0-RC.1(svelte@5.25.3)':
dependencies:
@@ -3654,7 +3654,7 @@ snapshots:
'@appwrite.io/pink-icons': 1.0.0
the-new-css-reset: 1.11.3
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@4e03f34(svelte@5.25.3)':
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@40bae6b(svelte@5.25.3)':
dependencies:
'@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3)
'@floating-ui/dom': 1.6.13
+7 -6
View File
@@ -167,13 +167,10 @@
<div style="padding: 1rem; padding-block-end: 0;">
<Alert.Inline
dismissible
title="We collect user responses to refine our experimental AI feature."
on:dismiss={() => {
$preferences.hideAiDisclaimer = true;
}}>
<span slot="title">
We collect user responses to refine our experimental AI feature.
</span>
</Alert.Inline>
}} />
</div>
{/if}
@@ -229,8 +226,11 @@
<Layout.Stack direction="row" gap="s">
<AvatarInitials size="s" name={$user.name} />
<form
class="input-text-wrapper u-width-full-line"
class="u-full-width input-text-wrapper"
style="--amount-of-buttons: 1;"
style:display="flex"
style:width="100%"
style:align-items="center"
on:submit|preventDefault={(e) => {
handleSubmit(e);
}}>
@@ -238,6 +238,7 @@
<input
type="text"
class="input-text"
style:width="100%"
placeholder="Ask a question..."
autofocus
bind:value={$input}
@@ -22,8 +22,7 @@
const alertHeight = container?.getBoundingClientRect()?.height || 0;
const { header, sidebar, content } = queryLayoutElements();
const headerHeight = header?.getBoundingClientRect().height || 0;
const offset = alertHeight + (!isTabletViewport && header ? headerHeight : 0);
const offset = alertHeight + (!$isTabletViewport && header ? headerHeight : 0);
if (header) header.style.top = `${alertHeight}px`;
if (sidebar) {
sidebar.style.top = `${offset}px`;
+69 -100
View File
@@ -23,14 +23,13 @@
Navbar,
Icon,
Layout,
Link,
Tooltip,
Card,
ActionMenu,
ToggleButton,
Button,
Avatar,
Typography
Typography,
Popover
} from '@appwrite.io/pink-svelte';
import { toggleCommandCenter } from '$lib/commandCenter/commandCenter.svelte';
import {
@@ -209,91 +208,79 @@
</Button.Button>
<span slot="tooltip">{isMac() ? '⌘ + K' : 'Ctrl + K'}</span></Tooltip>
</Layout.Stack>
<Link.Button
on:click={() => {
showAccountMenu = !showAccountMenu;
shouldAnimateThemeToggle = false;
if (showAccountMenu) {
trackEvent(Click.MenuDropDownClick);
}
}}>
<div style:user-select="none">
<Popover let:toggle let:showing>
<button
type="button"
on:click|preventDefault={(e) => {
toggle(e);
shouldAnimateThemeToggle = false;
if (showing) {
trackEvent(Click.MenuDropDownClick);
}
}}
style:user-select="none">
<Avatar size="s" src={avatar} />
</div>
</Link.Button>
{#if showAccountMenu}
<div class="account-container">
<Card.Base padding="xxxs" shadow={true}>
</button>
<svelte:fragment slot="tooltip" let:toggle>
<ActionMenu.Root noPadding>
<Layout.Stack gap="xxs">
<ActionMenu.Root>
<Layout.Stack gap="xxs">
<div
style:padding-inline-start="10px"
style:padding-inline-end="8px"
style:padding-block="4px">
<Typography.Text variant="m-500">
{$user.email}
</Typography.Text>
</div>
<ActionMenu.Item.Anchor
trailingIcon={IconUser}
size="l"
href={`${base}/account`}>
Account</ActionMenu.Item.Anchor>
<div
style:padding-inline-start="10px"
style:padding-inline-end="8px"
style:padding-block="4px">
<Typography.Text variant="m-500">
{$user.email}
</Typography.Text>
</div>
<ActionMenu.Item.Anchor
trailingIcon={IconUser}
on:click={toggle}
size="l"
href={`${base}/account`}>
Account</ActionMenu.Item.Anchor>
<ActionMenu.Item.Button
trailingIcon={IconLogoutRight}
size="l"
on:click={() => logout()}>Sign out</ActionMenu.Item.Button>
<div
style:padding-inline-start="10px"
style:padding-inline-end="8px">
<Layout.Stack
justifyContent="space-between"
direction="row"
alignItems="center">
<Typography.Text>Theme</Typography.Text>
<div
class:keepTransformTransition={shouldAnimateThemeToggle}>
<ToggleButton
bind:active={activeTheme}
on:change={() => {
setTimeout(() => {
shouldAnimateThemeToggle = true;
}, 150);
}}
buttons={[
{
id: 'light',
label: 'Light',
icon: IconSun
},
{
id: 'dark',
label: 'Dark',
icon: IconMoon
},
{
id: 'auto',
label: 'System',
icon: IconMode
}
]}></ToggleButton>
</div>
</Layout.Stack>
<ActionMenu.Item.Button
trailingIcon={IconLogoutRight}
size="l"
on:click={() => logout()}>Sign out</ActionMenu.Item.Button>
<div style:padding-inline-start="10px" style:padding-inline-end="8px">
<Layout.Stack
justifyContent="space-between"
direction="row"
alignItems="center">
<Typography.Text>Theme</Typography.Text>
<div class:keepTransformTransition={shouldAnimateThemeToggle}>
<ToggleButton
bind:active={activeTheme}
on:change={() => {
setTimeout(() => {
shouldAnimateThemeToggle = true;
}, 150);
}}
buttons={[
{
id: 'light',
label: 'Light',
icon: IconSun
},
{
id: 'dark',
label: 'Dark',
icon: IconMoon
},
{
id: 'auto',
label: 'System',
icon: IconMode
}
]}></ToggleButton>
</div>
</Layout.Stack>
</ActionMenu.Root>
</div>
</Layout.Stack>
</Card.Base>
</div>
<button
class="account-backdrop"
aria-label="Account menu"
on:click={() => {
showAccountMenu = false;
}}></button>
{/if}
</ActionMenu.Root>
</svelte:fragment>
</Popover>
</div>
</div>
</Navbar.Base>
@@ -405,24 +392,6 @@
}
}
.account-container {
position: absolute;
right: var(--space-7);
top: var(--base-44);
width: 244px;
display: flex;
z-index: 1;
}
.account-backdrop {
position: absolute;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background-color: transparent;
}
/* The default drop list has a max-inline width of 280px, which squeezes the support modal. */
:global(.extended-width) {
max-inline-size: none;
+1
View File
@@ -275,6 +275,7 @@ export function isServiceLimited(serviceId: PlanServices, plan: Tier, total: num
}
export function checkForEnterpriseTrial(org: Organization) {
if (!org || !org.billingNextInvoiceDate) return;
if (calculateEnterpriseTrial(org) > 0) {
headerAlert.add({
id: 'teamEnterpriseTrial',
@@ -20,7 +20,7 @@
let error: string;
let showCustomId = false;
let disabled: boolean = false;
let name: string = 'Appwrite project';
let name: string = 'New project';
async function create() {
try {
@@ -17,7 +17,7 @@
export let showCreateProjectCloud: boolean;
let id: string = null;
let name: string = 'Appwrite project';
let name: string = 'New project';
let region: string = Region.Fra;
let error: string = null;
@@ -8,7 +8,7 @@
import { isTabSelected } from '$lib/helpers/load';
import { Cover } from '$lib/layout';
import { daysLeftInTrial, getServiceLimit, plansInfo, readOnly } from '$lib/stores/billing';
import { members, newMemberModal, organization } from '$lib/stores/organization';
import { members, newMemberModal, type Organization } from '$lib/stores/organization';
import {
canSeeBilling,
canSeeProjects,
@@ -18,20 +18,21 @@
} from '$lib/stores/roles';
import { GRACE_PERIOD_OVERRIDE, isCloud } from '$lib/system';
import { IconGithub, IconPlus } from '@appwrite.io/pink-icons-svelte';
import { Icon, Tooltip, Typography, Layout, Badge } from '@appwrite.io/pink-svelte';
import { Badge, Icon, Layout, Tooltip, Typography } from '@appwrite.io/pink-svelte';
let areMembersLimited: boolean;
$: organization.subscribe(() => {
$: {
const limit = getServiceLimit('members') || Infinity;
const isLimited = limit !== 0 && limit < Infinity;
areMembersLimited =
isCloud &&
(($readOnly && !GRACE_PERIOD_OVERRIDE) || (isLimited && $members?.total >= limit));
});
}
$: organization = page.data.organization as Organization;
$: avatars = $members.memberships?.map((m) => m.userName || m.userEmail) ?? [];
$: organizationId = $organization?.$id ?? page.params.organization;
$: path = `${base}/organization-${organizationId}`;
$: path = `${base}/organization-${organization.$id}`;
$: tabs = [
{
href: path,
@@ -75,26 +76,26 @@
].filter((tab) => !tab.disabled);
</script>
{#if $organization.$id}
{#if organization?.$id}
<Cover>
<svelte:fragment slot="header">
<span class="u-flex u-cross-center u-gap-8 u-min-width-0">
<Typography.Title color="--fgcolor-neutral-primary" size="xl" truncate>
{$organization.name}
{organization.name}
</Typography.Title>
{#if isCloud && $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
{#if isCloud && organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
<Badge variant="secondary" content="Education">
<Icon icon={IconGithub} size="s" slot="start" />
</Badge>
{:else if isCloud && $organization?.billingPlan === BillingPlan.FREE}
{:else if isCloud && organization?.billingPlan === BillingPlan.FREE}
<Badge variant="secondary" content="Free"></Badge>
{/if}
{#if isCloud && $organization?.billingTrialStartDate && $daysLeftInTrial > 0 && $organization.billingPlan !== BillingPlan.FREE && $plansInfo.get($organization.billingPlan)?.trialDays}
{#if isCloud && organization?.billingTrialStartDate && $daysLeftInTrial > 0 && organization.billingPlan !== BillingPlan.FREE && $plansInfo.get(organization.billingPlan)?.trialDays}
<Tooltip>
<Badge variant="secondary" content="Trial" />
<svelte:fragment slot="tooltip">
{`Your trial ends on ${toLocaleDate(
$organization.billingStartDate
organization.billingStartDate
)}. ${$daysLeftInTrial} days remaining.`}
</svelte:fragment>
</Tooltip>
@@ -11,7 +11,7 @@
import { sortBranches } from '$lib/stores/vcs';
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
import { LabelCard } from '$lib/components';
import { Runtime, StatusCode, type Models } from '@appwrite.io/console';
import { type Models, ProxyResourceType, Runtime, StatusCode } from '@appwrite.io/console';
import { statusCodeOptions } from '$lib/stores/domains';
import { writable } from 'svelte/store';
import { onMount } from 'svelte';
@@ -48,18 +48,21 @@
async function addDomain() {
const apexDomain = getApexDomain(domainName);
let domain = data.domains?.domains.find((d) => d.domain === apexDomain);
let domain = data.domains?.domains.find((d: Models.Domain) => d.domain === apexDomain);
if (apexDomain && !domain && isCloud) {
try {
domain = await sdk.forConsole.domains.create($project.teamId, apexDomain);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
return;
// apex might already be added on organization level, skip.
const alreadyAdded = error?.type === 'domain_already_exists';
if (!alreadyAdded) {
addNotification({
type: 'error',
message: error.message
});
return;
}
}
}
@@ -72,7 +75,13 @@
} else if (behaviour === 'REDIRECT') {
rule = await sdk
.forProject(page.params.region, page.params.project)
.proxy.createRedirectRule(domainName, redirect, statusCode);
.proxy.createRedirectRule(
domainName,
redirect,
statusCode,
page.params.function,
ProxyResourceType.Function
);
} else if (behaviour === 'ACTIVE') {
rule = await sdk
.forProject(page.params.region, page.params.project)
@@ -12,6 +12,7 @@
import { isCloud } from '$lib/system';
import { project } from '$routes/(console)/project-[region]-[project]/store';
import { getApexDomain } from '$lib/helpers/tlds';
import type { Models } from '@appwrite.io/console';
const routeBase = `${base}/project-${page.params.region}-${page.params.project}/settings/domains`;
@@ -29,18 +30,21 @@
async function addDomain() {
const apexDomain = getApexDomain(domainName);
let domain = data.domains?.domains.find((d) => d.domain === apexDomain);
let domain = data.domains?.domains.find((d: Models.Domain) => d.domain === apexDomain);
if (apexDomain && !domain && isCloud) {
try {
domain = await sdk.forConsole.domains.create($project.teamId, apexDomain);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
return;
// apex might already be added on organization level, skip.
const alreadyAdded = error?.type === 'domain_already_exists';
if (!alreadyAdded) {
addNotification({
type: 'error',
message: error.message
});
return;
}
}
}
@@ -26,18 +26,10 @@ export const load = async ({ params, depends, url, route }) => {
.forProject(params.region, params.project)
.proxy.listRules(
[
Query.or([
Query.and([
Query.equal('type', RuleType.REDIRECT),
Query.equal('trigger', RuleTrigger.MANUAL)
]),
Query.and([
Query.equal('type', RuleType.DEPLOYMENT),
Query.equal('trigger', RuleTrigger.MANUAL),
Query.equal('deploymentResourceType', DeploymentResourceType.SITE),
Query.equal('deploymentResourceId', params.site)
])
]),
Query.equal('type', [RuleType.DEPLOYMENT, RuleType.REDIRECT]),
Query.equal('deploymentResourceType', DeploymentResourceType.SITE),
Query.equal('deploymentResourceId', params.site),
Query.equal('trigger', RuleTrigger.MANUAL),
Query.limit(limit),
Query.offset(offset),
Query.orderDesc(''),
@@ -16,13 +16,17 @@
BuildRuntime,
Framework,
type Models,
ProxyResourceType,
StatusCode
} from '@appwrite.io/console';
import { statusCodeOptions } from '$lib/stores/domains';
import { writable } from 'svelte/store';
import { onMount } from 'svelte';
import { ConnectRepoModal } from '$lib/components/git/index.js';
import { project } from '$routes/(console)/project-[region]-[project]/store';
import {
project,
regionalConsoleVariables
} from '$routes/(console)/project-[region]-[project]/store';
import { isCloud } from '$lib/system';
import { getApexDomain } from '$lib/helpers/tlds';
@@ -53,17 +57,23 @@
async function addDomain() {
const apexDomain = getApexDomain(domainName);
let domain = data.domains?.domains.find((d) => d.domain === apexDomain);
let domain = data.domains?.domains.find((d: Models.Domain) => d.domain === apexDomain);
if (apexDomain && !domain && isCloud) {
const isSiteDomain = domainName.endsWith($regionalConsoleVariables._APP_DOMAIN_SITES);
if (isCloud && apexDomain && !domain && !isSiteDomain) {
try {
domain = await sdk.forConsole.domains.create($project.teamId, apexDomain);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
return;
// apex might already be added on organization level, skip.
const alreadyAdded = error?.type === 'domain_already_exists';
if (!alreadyAdded) {
addNotification({
type: 'error',
message: error.message
});
return;
}
}
}
@@ -76,7 +86,13 @@
} else if (behaviour === 'REDIRECT') {
rule = await sdk
.forProject(page.params.region, page.params.project)
.proxy.createRedirectRule(domainName, redirect, statusCode);
.proxy.createRedirectRule(
domainName,
redirect,
statusCode,
page.params.site,
ProxyResourceType.Site
);
} else if (behaviour === 'ACTIVE') {
rule = await sdk
.forProject(page.params.region, page.params.project)
@@ -107,7 +107,7 @@
helper="Password must be at least 8 characters long"
required
bind:value={pass} />
<InputChoice required value={terms} id="terms" label="terms" showLabel={false}>
<InputChoice required bind:value={terms} id="terms" label="terms" showLabel={false}>
By registering, you agree that you have read, understand, and acknowledge our <Link.Anchor
href="https://appwrite.io/privacy"
target="_blank"
@@ -119,10 +119,16 @@
target="_blank"
rel="noopener noreferrer">General Terms of Use</Link.Anchor
>.</InputChoice>
<Button fullWidth submit {disabled}>Sign up</Button>
<Button fullWidth submit disabled={disabled || !terms}>Sign up</Button>
{#if isCloud}
<span class="with-separators eyebrow-heading-3">or</span>
<Button secondary fullWidth on:click={onGithubLogin} {disabled}>
<Button
secondary
fullWidth
on:click={onGithubLogin}
disabled={disabled || !terms}>
<span class="icon-github" aria-hidden="true"></span>
<span class="text">Sign up with GitHub</span>
</Button>