mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'main' into feat-database-backups.
This commit is contained in:
commit
e4e8a9cdb4
49 files changed
+1017
-761
No files matched your search
+7
-7
@@ -19,11 +19,11 @@
|
||||
"e2e:ui": "playwright test tests/e2e --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "^1.2.0",
|
||||
"@appwrite.io/console": "^1.2.2",
|
||||
"@appwrite.io/pink": "0.25.0",
|
||||
"@appwrite.io/pink-icons": "0.25.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/sveltekit": "^8.32.0",
|
||||
"@sentry/sveltekit": "^8.33.1",
|
||||
"@stripe/stripe-js": "^3.5.0",
|
||||
"ai": "^2.2.37",
|
||||
"analytics": "^0.8.14",
|
||||
@@ -42,13 +42,13 @@
|
||||
"devDependencies": {
|
||||
"@melt-ui/pp": "^0.3.2",
|
||||
"@melt-ui/svelte": "^0.83.0",
|
||||
"@playwright/test": "^1.47.2",
|
||||
"@playwright/test": "^1.48.0",
|
||||
"@sveltejs/adapter-static": "^3.0.5",
|
||||
"@sveltejs/kit": "^2.6.0",
|
||||
"@sveltejs/kit": "^2.6.3",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/jest-dom": "^6.5.0",
|
||||
"@testing-library/svelte": "^5.2.1",
|
||||
"@testing-library/svelte": "^5.2.3",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/deep-equal": "^1.0.4",
|
||||
"@types/prismjs": "^1.26.4",
|
||||
@@ -62,12 +62,12 @@
|
||||
"kleur": "^4.1.5",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-svelte": "^3.2.7",
|
||||
"sass": "^1.79.3",
|
||||
"sass": "^1.79.4",
|
||||
"svelte": "^4.2.19",
|
||||
"svelte-check": "^3.8.6",
|
||||
"svelte-jester": "^2.3.2",
|
||||
"svelte-preprocess": "^6.0.3",
|
||||
"svelte-sequential-preprocessor": "^2.0.1",
|
||||
"svelte-sequential-preprocessor": "^2.0.2",
|
||||
"tslib": "^2.7.0",
|
||||
"typescript": "^5.6.2",
|
||||
"vite": "^5.4.8",
|
||||
|
||||
Generated
+629
-619
File diff suppressed because it is too large.
Load diff
@@ -5,10 +5,12 @@
|
||||
|
||||
export let series: BarSeriesOption[];
|
||||
export let options: EChartsOption = null;
|
||||
export let formatted: 'days' | 'hours' = 'days';
|
||||
</script>
|
||||
|
||||
<Base
|
||||
{options}
|
||||
{formatted}
|
||||
series={series.map((s) => {
|
||||
s.type = 'bar';
|
||||
s.stack = 'total';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { registerTheme, use, init } from 'echarts/core';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { app } from '$lib/stores/app';
|
||||
import { defaultConfig } from './config';
|
||||
import { dailyFormat, hourlyFormat, defaultConfig } from './config';
|
||||
import base from './base.json';
|
||||
import light from './light.json';
|
||||
import dark from './dark.json';
|
||||
@@ -16,12 +16,14 @@
|
||||
|
||||
export let options: EChartsOption;
|
||||
export let series: (BarSeriesOption | LineSeriesOption)[];
|
||||
export let formatted: 'days' | 'hours' = 'days';
|
||||
|
||||
let chart: ECharts;
|
||||
let container: HTMLDivElement;
|
||||
|
||||
$: option = {
|
||||
...defaultConfig,
|
||||
...(formatted === 'days' ? dailyFormat : hourlyFormat),
|
||||
...options,
|
||||
series
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { toLocaleDate, toLocaleDateTime } from '$lib/helpers/date';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
|
||||
export enum Colors {
|
||||
@@ -10,9 +11,6 @@ export enum Colors {
|
||||
export const defaultConfig: EChartsOption = {
|
||||
color: Object.values(Colors),
|
||||
animation: false,
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
grid: {
|
||||
containLabel: true,
|
||||
left: 0,
|
||||
@@ -35,3 +33,31 @@ export const defaultConfig: EChartsOption = {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const dailyFormat: EChartsOption = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
label: {
|
||||
formatter: function (params) {
|
||||
const date = new Date(params.value);
|
||||
return toLocaleDate(date.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const hourlyFormat: EChartsOption = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
label: {
|
||||
formatter: function (params) {
|
||||
const date = new Date(params.value);
|
||||
return toLocaleDateTime(date.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -6,10 +6,12 @@
|
||||
|
||||
export let series: LineSeriesOption[];
|
||||
export let options: EChartsOption = null;
|
||||
export let formatted: 'days' | 'hours' = 'days';
|
||||
</script>
|
||||
|
||||
<Base
|
||||
{options}
|
||||
{formatted}
|
||||
series={series.map((s) => {
|
||||
s.type = 'line';
|
||||
s.stack = 'total';
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
export let billingPlan: Tier;
|
||||
export let anyOrgFree = false;
|
||||
export let isNewOrg = false;
|
||||
export let selfService = true;
|
||||
let classes: string = '';
|
||||
export { classes as class };
|
||||
|
||||
@@ -22,7 +23,7 @@
|
||||
<LabelCard
|
||||
name="plan"
|
||||
bind:group={billingPlan}
|
||||
disabled={anyOrgFree}
|
||||
disabled={anyOrgFree || !selfService}
|
||||
value={BillingPlan.FREE}
|
||||
tooltipShow={anyOrgFree}
|
||||
tooltipText="You are limited to 1 Free organization per account."
|
||||
@@ -49,9 +50,16 @@
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<LabelCard name="plan" bind:group={billingPlan} value={BillingPlan.PRO} padding={1.5}>
|
||||
<svelte:fragment slot="custom">
|
||||
<div class="u-flex u-flex-vertical u-gap-4 u-width-full-line">
|
||||
<LabelCard
|
||||
name="plan"
|
||||
disabled={!selfService}
|
||||
bind:group={billingPlan}
|
||||
value={BillingPlan.PRO}
|
||||
padding={1.5}>
|
||||
<svelte:fragment slot="custom" let:disabled>
|
||||
<div
|
||||
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
|
||||
class:u-opacity-50={disabled}>
|
||||
<h4 class="body-text-2 u-bold">
|
||||
{tierPro.name}
|
||||
{#if $organization?.billingPlan === BillingPlan.PRO && !isNewOrg}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import { addBottomModalAlerts } from '$routes/(console)/bottomAlerts';
|
||||
import { project } from '$routes/(console)/project-[project]/store';
|
||||
import { page } from '$app/stores';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
let currentIndex = 0;
|
||||
let openModalOnMobile = false;
|
||||
@@ -50,16 +51,12 @@
|
||||
$: currentModalAlert = filteredModalAlerts[currentIndex] as BottomModalAlertItem;
|
||||
|
||||
function handleClose() {
|
||||
const modalAlert = currentModalAlert;
|
||||
dismissBottomModalAlert(modalAlert.id);
|
||||
hideNotification(modalAlert.id, { coolOffPeriod: 24 * 365 });
|
||||
if (modalAlert.closed) modalAlert.closed();
|
||||
|
||||
if (currentIndex === filteredModalAlerts.length - 1 && filteredModalAlerts.length > 1) {
|
||||
currentIndex = currentIndex - 1;
|
||||
} else {
|
||||
currentIndex = currentIndex % filteredModalAlerts.length;
|
||||
}
|
||||
filteredModalAlerts.forEach((alert) => {
|
||||
const modalAlert = alert;
|
||||
dismissBottomModalAlert(modalAlert.id);
|
||||
hideNotification(modalAlert.id, { coolOffPeriod: 24 * 365 });
|
||||
if (modalAlert.closed) modalAlert.closed();
|
||||
});
|
||||
}
|
||||
|
||||
function showNext() {
|
||||
@@ -171,7 +168,13 @@
|
||||
project: $project
|
||||
})}
|
||||
external={!!currentModalAlert.cta.external}
|
||||
fullWidthMobile>
|
||||
fullWidthMobile
|
||||
on:click={() => {
|
||||
trackEvent('click_promo', {
|
||||
promo: currentModalAlert.id,
|
||||
type: shouldShowUpgrade ? 'upgrade' : 'try_now'
|
||||
});
|
||||
}}>
|
||||
{currentModalAlert.cta.text}
|
||||
</Button>
|
||||
|
||||
@@ -277,7 +280,13 @@
|
||||
})}
|
||||
external={!!currentModalAlert.cta.external}
|
||||
fullWidthMobile
|
||||
on:click={() => (openModalOnMobile = false)}>
|
||||
on:click={() => {
|
||||
openModalOnMobile = false;
|
||||
trackEvent('click_promo', {
|
||||
promo: currentModalAlert.id,
|
||||
type: shouldShowUpgrade ? 'upgrade' : 'try_now'
|
||||
});
|
||||
}}>
|
||||
{shouldShowUpgrade
|
||||
? 'Upgrade plan'
|
||||
: currentModalAlert.cta.text}
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
: selected.service?.actions;
|
||||
|
||||
// We need to check if the selected action name is still
|
||||
// on the available list, and if so, change tje action to the
|
||||
// on the available list, and if so, change the action to the
|
||||
// appropriate one, as it may contain different attributes
|
||||
const availableAction = availableActions.find(
|
||||
(a) => a.name === selected.action?.name
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
<Modal
|
||||
title="Label"
|
||||
description="Labels allow you to grant access to users with the specfied label."
|
||||
description="Labels allow you to grant access to users with the specified label."
|
||||
bind:show
|
||||
on:close={reset}
|
||||
onSubmit={create}>
|
||||
|
||||
@@ -468,7 +468,8 @@ export const eventServices: Array<EventService> = [
|
||||
export enum BillingPlan {
|
||||
FREE = 'tier-0',
|
||||
PRO = 'tier-1',
|
||||
SCALE = 'tier-2'
|
||||
SCALE = 'tier-2',
|
||||
CUSTOM = 'cont-1'
|
||||
}
|
||||
|
||||
export const feedbackDowngradeOptions = [
|
||||
|
||||
@@ -51,7 +51,7 @@ export const toLocaleDateTime = (datetime: string | number) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a date string usig the local timezone in ISO format (yyyy-mm-dd)
|
||||
* Returns a date string using the local timezone in ISO format (yyyy-mm-dd)
|
||||
*
|
||||
* @param datetime date string or milliseconds since the epoch
|
||||
*/
|
||||
@@ -67,7 +67,7 @@ export const toLocaleDateISO = (datetime: string | number) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a time string usig the local timezone in ISO format (hh:mm:ss)
|
||||
* Returns a time string using the local timezone in ISO format (hh:mm:ss)
|
||||
*
|
||||
* @param datetime date string or milliseconds since the epoch
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<footer class="main-footer u-cross-center">
|
||||
<div class="main-footer-start">
|
||||
<ul class="inline-links is-no-padding-first-and-last u-x-small u-flex-wrap u-row-gap-16">
|
||||
<ul class="inline-links is-no-padding-first-and-last u-x-small u-flex-wrap u-gap-16">
|
||||
<li class="inline-links-item" style="line-height: 1.02;">
|
||||
<div class="u-flex u-cross-center u-gap-8">
|
||||
{#if isCloud}
|
||||
@@ -79,7 +79,18 @@
|
||||
margin-block-start: auto;
|
||||
}
|
||||
|
||||
.main-footer-start .inline-links-item {
|
||||
padding-inline-end: 1rem;
|
||||
padding-inline-start: unset;
|
||||
}
|
||||
|
||||
[class^='icon-']:not(.icon-cloud):not(:hover) {
|
||||
color: hsl(var(--color-neutral-50));
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.main-footer {
|
||||
gap: 2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -48,6 +48,10 @@
|
||||
return queries;
|
||||
}
|
||||
|
||||
function unescapeNewLines(logs: string) {
|
||||
return logs.replace(/\\n/g, '\n');
|
||||
}
|
||||
|
||||
beforeNavigate((n) => {
|
||||
if (!$log.show) return;
|
||||
if (n.type === 'popstate') {
|
||||
@@ -343,7 +347,11 @@
|
||||
{/if}
|
||||
</Alert>
|
||||
{/if}
|
||||
<Code withCopy noMargin code={execution.logs} language="sh" />
|
||||
<Code
|
||||
withCopy
|
||||
noMargin
|
||||
code={unescapeNewLines(execution.logs)}
|
||||
language="sh" />
|
||||
{:else}
|
||||
<Card isDashed isTile>
|
||||
<p class="text u-text-center">No response was recorded.</p>
|
||||
@@ -351,7 +359,11 @@
|
||||
{/if}
|
||||
{:else if selectedResponse === 'errors'}
|
||||
{#if execution?.errors}
|
||||
<Code withCopy noMargin code={execution.errors} language="sh" />
|
||||
<Code
|
||||
withCopy
|
||||
noMargin
|
||||
code={unescapeNewLines(execution.errors)}
|
||||
language="sh" />
|
||||
{:else}
|
||||
<Card isDashed isTile>
|
||||
<p class="text u-text-center">No response was recorded.</p>
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
<div class="u-margin-block-start-16" />
|
||||
<div class="chart-container">
|
||||
<BarChart
|
||||
formatted={$page.params.period === '24h' ? 'hours' : 'days'}
|
||||
series={[
|
||||
{
|
||||
name: countMetadata.legend,
|
||||
|
||||
@@ -146,7 +146,7 @@ export type Aggregation = {
|
||||
*/
|
||||
amount: number;
|
||||
/**
|
||||
* Price for addional members
|
||||
* Price for additional members
|
||||
*/
|
||||
additionalMembers: number;
|
||||
/**
|
||||
@@ -277,6 +277,8 @@ export type Plan = {
|
||||
users: AdditionalResource;
|
||||
};
|
||||
trialDays: number;
|
||||
isAvailable: boolean;
|
||||
selfService: boolean;
|
||||
};
|
||||
|
||||
export type PlansInfo = {
|
||||
|
||||
@@ -34,7 +34,7 @@ import { user } from './user';
|
||||
import { browser } from '$app/environment';
|
||||
import { canSeeBilling } from './roles';
|
||||
|
||||
export type Tier = 'tier-0' | 'tier-1' | 'tier-2';
|
||||
export type Tier = 'tier-0' | 'tier-1' | 'tier-2' | 'cont-1';
|
||||
|
||||
export const roles = [
|
||||
{
|
||||
@@ -77,6 +77,8 @@ export function tierToPlan(tier: Tier) {
|
||||
return tierPro;
|
||||
case BillingPlan.SCALE:
|
||||
return tierScale;
|
||||
case BillingPlan.CUSTOM:
|
||||
return tierCustom;
|
||||
default:
|
||||
return tierFree;
|
||||
}
|
||||
@@ -182,6 +184,11 @@ export const tierScale: TierData = {
|
||||
description: 'For scaling teams and agencies that need dedicated support.'
|
||||
};
|
||||
|
||||
export const tierCustom: TierData = {
|
||||
name: 'Custom',
|
||||
description: 'Team on a custom contract'
|
||||
};
|
||||
|
||||
export const showUsageRatesModal = writable<boolean>(false);
|
||||
|
||||
export function checkForUsageFees(plan: Tier, id: PlanServices) {
|
||||
|
||||
@@ -31,7 +31,7 @@ function createHeaderAlertStore() {
|
||||
});
|
||||
},
|
||||
get: (): HeaderAlert => {
|
||||
//return higest importance component
|
||||
//return highest importance component
|
||||
let component = {
|
||||
id: '',
|
||||
show: false,
|
||||
|
||||
@@ -36,7 +36,7 @@ export async function initializeStripe() {
|
||||
// Set up the options for the stripe elements
|
||||
const options = {
|
||||
clientSecret: clientSecret,
|
||||
appearance: get(app).themeInUse === 'dark' ? apperanceDark : apperanceLight
|
||||
appearance: get(app).themeInUse === 'dark' ? appearanceDark : appearanceLight
|
||||
};
|
||||
// Set up Elements and then create form
|
||||
elements = get(stripe).elements(options);
|
||||
@@ -184,7 +184,7 @@ export async function confirmSetup(
|
||||
}
|
||||
}
|
||||
|
||||
const apperanceLight = {
|
||||
const appearanceLight = {
|
||||
variables: {
|
||||
colorPrimary: '#606a7b',
|
||||
colorText: 'rgb(107, 107, 112)',
|
||||
@@ -213,7 +213,7 @@ const apperanceLight = {
|
||||
}
|
||||
};
|
||||
|
||||
const apperanceDark = {
|
||||
const appearanceDark = {
|
||||
variables: {
|
||||
colorPrimary: '#606a7b',
|
||||
colorText: 'rgb(195, 195, 198)',
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
</div>
|
||||
<div class="body-text-2">
|
||||
{runtimeDetail.name}
|
||||
{#if runtimeDetail.name.toLowerCase() === 'go'}
|
||||
{#if runtimeDetail.name.toLowerCase() === 'deno'}
|
||||
<span class="inline-tag">New</span>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -192,7 +192,7 @@
|
||||
<Button
|
||||
text
|
||||
class="u-margin-block-start-24 u-margin-inline-start-auto"
|
||||
href={`${base}/project-${$page.params.project}/functions/templates?useCase=Starter`}>
|
||||
href={`${base}/project-${$page.params.project}/functions/templates?useCase=starter`}>
|
||||
All starter templates <span class="icon-cheveron-right" />
|
||||
</Button>
|
||||
<div class="u-sep-block-start common-section" />
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
/**
|
||||
*
|
||||
* @param field {string} The field to update.
|
||||
* Representes the path to the field in the formData object e.g. 'users.root'
|
||||
* Represents the path to the field in the formData object e.g. 'users.root'
|
||||
*/
|
||||
function handleInputChange(field: FormKeys) {
|
||||
return (event: Event) => {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
async function updateEmail() {
|
||||
try {
|
||||
await sdk.forConsole.account.updateEmail(email, emailPassword);
|
||||
await invalidate(Dependencies.ACCOUNT);
|
||||
await Promise.all([invalidate(Dependencies.ACCOUNT), invalidate(Dependencies.FACTORS)]);
|
||||
addNotification({
|
||||
message: 'Email has been updated',
|
||||
type: 'success'
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import MfaRegenerateCodes from './mfaRegenerateCodes.svelte';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { page } from '$app/stores';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let showSetup: boolean = false;
|
||||
let showDelete: boolean = false;
|
||||
@@ -26,6 +28,56 @@
|
||||
.map(([factor, _]) => factor);
|
||||
$: enabledMethods = enabledFactors.filter((factor) => factor !== 'recoveryCode');
|
||||
|
||||
$: cleanUrl = $page.url.origin + $page.url.pathname;
|
||||
|
||||
let creatingVerification = false;
|
||||
|
||||
async function createVerification() {
|
||||
creatingVerification = true;
|
||||
|
||||
try {
|
||||
await sdk.forConsole.account.createVerification(cleanUrl);
|
||||
addNotification({
|
||||
message: 'Verification email has been sent',
|
||||
type: 'success'
|
||||
});
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
message: error.message,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
creatingVerification = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function updateEmailVerification() {
|
||||
const searchParams = $page.url.searchParams;
|
||||
const userId = searchParams.get('userId');
|
||||
const secret = searchParams.get('secret');
|
||||
|
||||
history.replaceState(null, '', cleanUrl);
|
||||
|
||||
if (userId && secret) {
|
||||
try {
|
||||
await sdk.forConsole.account.updateVerification(userId, secret);
|
||||
addNotification({
|
||||
message: 'Email verified successfully',
|
||||
type: 'success'
|
||||
});
|
||||
await Promise.all([
|
||||
invalidate(Dependencies.ACCOUNT),
|
||||
invalidate(Dependencies.FACTORS)
|
||||
]);
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
message: error.message,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function updateMfa() {
|
||||
try {
|
||||
await sdk.forConsole.account.updateMFA(!$user.mfa);
|
||||
@@ -77,6 +129,10 @@
|
||||
$: if (!showRecoveryCodes) {
|
||||
codes = null;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
updateEmailVerification();
|
||||
});
|
||||
</script>
|
||||
|
||||
<CardGrid>
|
||||
@@ -159,13 +215,34 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else if !$user.emailVerification}
|
||||
<div
|
||||
class="u-flex u-main-space-between u-sep-block-end"
|
||||
style="padding-block-end: 16px">
|
||||
<div class="u-flex u-gap-8 u-cross-baseline">
|
||||
<div class="avatar is-size-x-small">
|
||||
<span class="icon-mail" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="u-flex-vertical u-gap-4">
|
||||
<div class="u-flex u-gap-4 u-cross-center">
|
||||
<span class="body-text-2 u-bold">Email</span>
|
||||
<Pill>unverified</Pill>
|
||||
</div>
|
||||
<span>Verify your email to receive login MFA codes.</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
secondary
|
||||
disabled={creatingVerification}
|
||||
on:click={() => createVerification()}>Verify</Button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $factors.phone}
|
||||
<div
|
||||
class="u-flex u-main-space-between u-sep-block-end"
|
||||
style="padding-block-end: 16px">
|
||||
<div class="u-flex u-gap-8">
|
||||
<div class="u-flex u-gap-8 u-cross-baseline">
|
||||
<div class="avatar is-size-x-small">
|
||||
<span class="icon-send" aria-hidden="true" />
|
||||
</div>
|
||||
|
||||
@@ -17,8 +17,8 @@ export const load: LayoutLoad = async ({ params, depends }) => {
|
||||
depends(Dependencies.ORGANIZATION);
|
||||
depends(Dependencies.MEMBERS);
|
||||
depends(Dependencies.PAYMENT_METHODS);
|
||||
let roles = isCloud ? [] : defaultScopes;
|
||||
let scopes = isCloud ? [] : defaultRoles;
|
||||
let roles = isCloud ? [] : defaultRoles;
|
||||
let scopes = isCloud ? [] : defaultScopes;
|
||||
|
||||
try {
|
||||
if (isCloud) {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
let currentInvoice: Invoice;
|
||||
let extraMembers = 0;
|
||||
let currentPlan;
|
||||
|
||||
const today = new Date();
|
||||
onMount(async () => {
|
||||
const invoices = await sdk.forConsole.billing.listInvoices($organization.$id, [
|
||||
@@ -26,9 +28,10 @@
|
||||
currentInvoice = invoices.invoices[0];
|
||||
const members = await sdk.forConsole.teams.listMemberships($organization.$id, []);
|
||||
extraMembers = members.total > 1 ? members.total - 1 : 0;
|
||||
|
||||
currentPlan = await sdk.forConsole.billing.getPlan($organization?.$id);
|
||||
});
|
||||
|
||||
$: currentPlan = $plansInfo?.get($organization?.billingPlan);
|
||||
$: extraUsage = (currentInvoice?.amount ?? 0) - (currentPlan?.price ?? 0);
|
||||
$: extraAddons = currentInvoice?.usage?.length ?? 0;
|
||||
$: isTrial =
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
|
||||
let feedbackDowngradeReason: string;
|
||||
let feedbackMessage: string;
|
||||
let selfService: boolean;
|
||||
|
||||
onMount(async () => {
|
||||
if ($page.url.searchParams.has('code')) {
|
||||
@@ -99,6 +100,9 @@
|
||||
} else {
|
||||
billingPlan = BillingPlan.PRO;
|
||||
}
|
||||
|
||||
const currentPlan = await sdk.forConsole.billing.getPlan($organization?.$id);
|
||||
selfService = currentPlan.selfService;
|
||||
});
|
||||
|
||||
async function loadPaymentMethods() {
|
||||
@@ -252,8 +256,14 @@
|
||||
For more details on our plans, visit our
|
||||
<Button href="https://appwrite.io/pricing" external link>pricing page</Button>.
|
||||
</p>
|
||||
{#if !selfService}
|
||||
<Alert class="u-position-relative u-margin-block-start-16" type="info"
|
||||
>Your contract is not eligible for manual changes. Please reach out to schedule
|
||||
a call or setup a dialog.</Alert>
|
||||
{/if}
|
||||
<PlanSelection
|
||||
bind:billingPlan
|
||||
bind:selfService
|
||||
anyOrgFree={!!anyOrgFree}
|
||||
class={anyOrgFree && billingPlan !== BillingPlan.FREE
|
||||
? 'u-margin-block-start-16'
|
||||
@@ -323,14 +333,14 @@
|
||||
{/if}
|
||||
</Form>
|
||||
<svelte:fragment slot="aside">
|
||||
{#if billingPlan !== BillingPlan.FREE && $organization.billingPlan !== billingPlan}
|
||||
{#if billingPlan !== BillingPlan.FREE && $organization.billingPlan !== billingPlan && $organization.billingPlan !== BillingPlan.CUSTOM}
|
||||
<EstimatedTotalBox
|
||||
{billingPlan}
|
||||
{collaborators}
|
||||
bind:couponData
|
||||
bind:billingBudget
|
||||
{isDowngrade} />
|
||||
{:else}
|
||||
{:else if $organization.billingPlan !== BillingPlan.CUSTOM}
|
||||
<PlanComparisonBox downgrade={isDowngrade} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
@@ -341,7 +351,7 @@
|
||||
<Button
|
||||
fullWidthMobile
|
||||
on:click={() => formComponent.triggerSubmit()}
|
||||
disabled={$isSubmitting || isButtonDisabled}>
|
||||
disabled={$isSubmitting || isButtonDisabled || !selfService}>
|
||||
Change plan
|
||||
</Button>
|
||||
</WizardSecondaryFooter>
|
||||
|
||||
@@ -8,16 +8,16 @@
|
||||
|
||||
<CardGrid>
|
||||
<div>
|
||||
<Heading tag="h6" size="7">Soc-2</Heading>
|
||||
<Heading tag="h6" size="7">SOC-2</Heading>
|
||||
</div>
|
||||
<p class="text">After requesting Soc-2, we will contact you via email for the next steps.</p>
|
||||
<p class="text">After requesting SOC-2, we will contact you via email for the next steps.</p>
|
||||
<svelte:fragment slot="aside">
|
||||
<Box>
|
||||
<h6>
|
||||
<b>Service Organization Control Type 2 (Soc-2)</b>
|
||||
<b>Service Organization Control Type 2 (SOC-2)</b>
|
||||
</h6>
|
||||
<p class="text u-margin-block-start-8">
|
||||
Soc-2 is a framework for managing and protecting sensitive information, ensuring
|
||||
SOC-2 is a framework for managing and protecting sensitive information, ensuring
|
||||
compliance with trust service criteria such as security, availability, processing
|
||||
integrity, confidentiality, and privacy.
|
||||
</p>
|
||||
@@ -27,7 +27,7 @@
|
||||
class="u-margin-block-start-16"
|
||||
on:click={() => (show = true)}
|
||||
event="request_soc-2">
|
||||
<span class="text">Request Soc-2</span>
|
||||
<span class="text">Request SOC-2</span>
|
||||
</Button>
|
||||
</Box>
|
||||
</svelte:fragment>
|
||||
|
||||
@@ -63,10 +63,10 @@
|
||||
subject: 'support',
|
||||
email: email,
|
||||
firstName: $user?.name ?? '',
|
||||
message: 'Soc-2',
|
||||
message: 'SOC-2',
|
||||
tags: ['cloud'],
|
||||
customFields: [
|
||||
{ id: '41612', value: 'Soc-2' },
|
||||
{ id: '41612', value: 'SOC-2' },
|
||||
{ id: '48493', value: $user?.name ?? '' },
|
||||
{ id: '48492', value: $organization?.$id ?? '' },
|
||||
{ id: '48490', value: $user?.$id ?? '' }
|
||||
@@ -99,7 +99,7 @@
|
||||
onSubmit={handleSubmit}
|
||||
size="big"
|
||||
headerDivider={false}
|
||||
title="Request Soc-2">
|
||||
title="Request SOC-2">
|
||||
<FormList>
|
||||
<InputEmail label="Email" placeholder="Enter email" id="email" bind:value={email} />
|
||||
<InputSelect
|
||||
|
||||
@@ -17,8 +17,8 @@ export const load: LayoutLoad = async ({ params, depends }) => {
|
||||
const newPrefs = { ...prefs, organization: project.teamId };
|
||||
sdk.forConsole.account.updatePrefs(newPrefs);
|
||||
preferences.loadTeamPrefs(project.teamId);
|
||||
let roles = isCloud ? [] : defaultScopes;
|
||||
let scopes = isCloud ? [] : defaultRoles;
|
||||
let roles = isCloud ? [] : defaultRoles;
|
||||
let scopes = isCloud ? [] : defaultScopes;
|
||||
if (isCloud) {
|
||||
const res = await sdk.forConsole.billing.getRoles(project.teamId);
|
||||
roles = res.roles;
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
Heading,
|
||||
ViewSelector,
|
||||
EmptyFilter,
|
||||
EmptySearch
|
||||
EmptySearch,
|
||||
DropList
|
||||
} from '$lib/components';
|
||||
import { Container } from '$lib/layout';
|
||||
import type { PageData } from './$types';
|
||||
@@ -14,15 +15,34 @@
|
||||
import { columns } from './store';
|
||||
import { View } from '$lib/helpers/load';
|
||||
import Create from './create.svelte';
|
||||
import { Pill } from '$lib/elements';
|
||||
|
||||
export let data: PageData;
|
||||
let showAdd = false;
|
||||
let showMoreInfo = false;
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<div class="u-flex u-flex-vertical">
|
||||
<div class="u-flex u-main-space-between u-cross-center">
|
||||
<Heading tag="h2" size="5">Targets</Heading>
|
||||
<div class="u-flex u-gap-16 u-cross-center">
|
||||
<Heading tag="h2" size="5">Targets</Heading>
|
||||
<DropList bind:show={showMoreInfo} width="16">
|
||||
<Pill button on:click={() => (showMoreInfo = !showMoreInfo)}>
|
||||
<span class="icon-info" />More info
|
||||
</Pill>
|
||||
<svelte:fragment slot="list">
|
||||
<slot name="tooltip">
|
||||
<p>
|
||||
User targets include emails, phone numbers, and devices with your
|
||||
app installed. These targets can subscribe to a topic and receive
|
||||
messages published to it.
|
||||
</p>
|
||||
</slot>
|
||||
</svelte:fragment>
|
||||
</DropList>
|
||||
</div>
|
||||
|
||||
<!-- TODO: Remove u-hide to add creating a target -->
|
||||
<div class="is-only-mobile u-hide">
|
||||
<Button on:click={() => (showAdd = true)} event="create_user_target">
|
||||
@@ -67,17 +87,16 @@
|
||||
</SearchQuery> -->
|
||||
<div class="u-flex u-gap-16 is-only-mobile u-margin-block-start-16">
|
||||
<div class="u-flex-basis-50-percent">
|
||||
<!-- TODO: fix width -->
|
||||
<ViewSelector
|
||||
view={View.Table}
|
||||
{columns}
|
||||
hideView
|
||||
allowNoColumns
|
||||
showColsTextMobile />
|
||||
showColsTextMobile
|
||||
fullWidthMobile />
|
||||
</div>
|
||||
<div class="u-flex-basis-50-percent">
|
||||
<!-- TODO: fix width -->
|
||||
<Filters query={data.query} {columns} />
|
||||
<Filters query={data.query} {columns} fullWidthMobile />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -111,7 +130,7 @@
|
||||
Need a hand? Check out our <Button
|
||||
link
|
||||
external
|
||||
href="http://appwrite.io/docs/products/messaging/targets"
|
||||
href="https://appwrite.io/docs/products/messaging/targets"
|
||||
text>
|
||||
documentation</Button
|
||||
>.
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { user } from './store';
|
||||
|
||||
let showVerifcationDropdown = false;
|
||||
let showVerificationDropdown = false;
|
||||
|
||||
async function updateVerificationEmail() {
|
||||
showVerifcationDropdown = false;
|
||||
showVerificationDropdown = false;
|
||||
try {
|
||||
await sdk.forProject.users.updateEmailVerification($user.$id, !$user.emailVerification);
|
||||
await invalidate(Dependencies.USER);
|
||||
@@ -33,7 +33,7 @@
|
||||
}
|
||||
}
|
||||
async function updateVerificationPhone() {
|
||||
showVerifcationDropdown = false;
|
||||
showVerificationDropdown = false;
|
||||
try {
|
||||
await sdk.forProject.users.updatePhoneVerification($user.$id, !$user.phoneVerification);
|
||||
await invalidate(Dependencies.USER);
|
||||
@@ -135,10 +135,10 @@
|
||||
</Button>
|
||||
{#if $user.status}
|
||||
{#if $user.phone && $user.email}
|
||||
<DropList bind:show={showVerifcationDropdown} placement="top-start">
|
||||
<DropList bind:show={showVerificationDropdown} placement="top-start">
|
||||
<Button
|
||||
secondary
|
||||
on:click={() => (showVerifcationDropdown = !showVerifcationDropdown)}>
|
||||
on:click={() => (showVerificationDropdown = !showVerificationDropdown)}>
|
||||
{$user.emailVerification && $user.phoneVerification ? 'Unverify' : 'Verify'}
|
||||
account
|
||||
</Button>
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@
|
||||
label="Elements"
|
||||
bind:tags={data.elements}
|
||||
placeholder="Add elements here"
|
||||
tooltip="Enum elements have a maxiumum length of 255 characters. This limit can not be exceeded."
|
||||
tooltip="Enum elements have a maximum length of 255 characters. This limit can not be exceeded."
|
||||
required>
|
||||
</InputTags>
|
||||
|
||||
|
||||
+1
-1
@@ -326,7 +326,7 @@
|
||||
<FormList>
|
||||
<InputTextarea
|
||||
label="Commands"
|
||||
placeholder="Enter an install commad (e.g. 'npm install')"
|
||||
placeholder="Enter an install command (e.g. 'npm install')"
|
||||
id="install"
|
||||
tooltip="Enter a single command or chain multiple commands with the && operator"
|
||||
bind:value={commands} />
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import { connectTemplate } from '$lib/wizards/functions/cover.svelte';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { functionsList } from '../store';
|
||||
import { debounce } from '$lib/helpers/debounce';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -29,7 +30,9 @@
|
||||
if (add) {
|
||||
target.searchParams.append(filter, value);
|
||||
} else {
|
||||
const previous = target.searchParams.getAll(filter).filter((n) => n !== value);
|
||||
const previous = target.searchParams
|
||||
.getAll(filter)
|
||||
.filter((n) => n.toLowerCase() !== value.toLowerCase());
|
||||
target.searchParams.delete(filter);
|
||||
previous.forEach((n) => target.searchParams.append(filter, n));
|
||||
}
|
||||
@@ -39,8 +42,7 @@
|
||||
|
||||
function clearSearch() {
|
||||
const target = new URL($page.url);
|
||||
target.searchParams.delete('page');
|
||||
target.searchParams.delete('search');
|
||||
target.search = '';
|
||||
goto(target.toString());
|
||||
}
|
||||
|
||||
@@ -70,24 +72,46 @@
|
||||
return 'dart';
|
||||
case runtime.includes('bun'):
|
||||
return 'bun';
|
||||
case runtime.includes('go'):
|
||||
return 'go';
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function applySearch(event: CustomEvent<string>) {
|
||||
const value = event.detail;
|
||||
const target = new URL($page.url);
|
||||
debounce(() => {
|
||||
const value = event.detail;
|
||||
const target = new URL($page.url);
|
||||
|
||||
if (value.length > 0) {
|
||||
target.searchParams.set('search', value);
|
||||
} else {
|
||||
target.searchParams.delete('search');
|
||||
}
|
||||
target.searchParams.delete('page');
|
||||
goto(target.toString(), { keepFocus: true });
|
||||
if (value.length > 0) {
|
||||
target.searchParams.set('search', value);
|
||||
} else {
|
||||
target.searchParams.delete('search');
|
||||
}
|
||||
target.searchParams.delete('page');
|
||||
goto(target.toString(), { keepFocus: true });
|
||||
}, 250)();
|
||||
}
|
||||
|
||||
$: isChecked = (useCase: string) => {
|
||||
return $page.url.searchParams
|
||||
.getAll('useCase')
|
||||
.some((param) => param.toLowerCase() === useCase.toLowerCase());
|
||||
};
|
||||
|
||||
$: getErrorMessage = () => {
|
||||
const searchParams = $page.url.searchParams;
|
||||
const paramsArray = Array.from(searchParams.entries());
|
||||
|
||||
if (paramsArray.length === 1) {
|
||||
const [_, value] = paramsArray[0];
|
||||
return `Sorry, we couldn't find "${value}".`;
|
||||
} else if (paramsArray.length > 1) {
|
||||
return `Sorry, we couldn't find any results with the applied filters.`;
|
||||
}
|
||||
};
|
||||
|
||||
$: buttonDisabled = isServiceLimited(
|
||||
'functions',
|
||||
$organization?.billingPlan,
|
||||
@@ -106,6 +130,7 @@
|
||||
<section>
|
||||
<InputSearch
|
||||
placeholder="Search templates"
|
||||
value={$page.url.searchParams.get('search')}
|
||||
on:clear={clearSearch}
|
||||
on:change={applySearch} />
|
||||
<div class="u-margin-block-start-24">
|
||||
@@ -119,11 +144,9 @@
|
||||
<input
|
||||
type="checkbox"
|
||||
class="is-small"
|
||||
value={$page.url.searchParams
|
||||
.getAll('useCase')
|
||||
.includes(useCase)}
|
||||
checked={isChecked(useCase)}
|
||||
on:change={(e) => applyFilter('useCase', useCase, e)} />
|
||||
<div class="u-trim-1">{useCase}</div>
|
||||
<span class="u-trim-1">{useCase}</span>
|
||||
</label>
|
||||
</li>
|
||||
{/each}
|
||||
@@ -246,8 +269,7 @@
|
||||
<EmptySearch hidePagination>
|
||||
<div class="common-section">
|
||||
<div class="u-text-center common-section">
|
||||
<b class="body-text-2 u-bold"
|
||||
>Sorry we couldn't find "{$page.url.searchParams.get('search')}"</b>
|
||||
<b class="body-text-2 u-bold">{getErrorMessage()}</b>
|
||||
<p>There are no templates that match your search.</p>
|
||||
</div>
|
||||
<div class="u-flex u-gap-16 common-section u-main-center">
|
||||
|
||||
@@ -35,9 +35,10 @@ export const load: PageLoad = async ({ url, route, depends, parent }) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
const filterLowerCases = filter.useCases.map((n) => n.toLowerCase());
|
||||
if (
|
||||
filter.useCases.length > 0 &&
|
||||
!template.useCases.some((n) => filter.useCases.includes(n))
|
||||
!template.useCases.some((n) => filterLowerCases.includes(n.toLowerCase()))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
The message has been processed with errors. Please refer to the logs below for more
|
||||
information.
|
||||
</p>
|
||||
<div style="max-inline-size: 524px">
|
||||
<Code language="html" code={errors.join('\n')} noMargin noBoxPadding allowScroll />
|
||||
<div style="max-inline-size: 524px" class="wrapped-code-block-for-multi-line">
|
||||
<Code language="html" code={errors.join('\n')} withCopy allowScroll />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,3 +28,12 @@
|
||||
<Button secondary on:click={() => (show = false)}>Close</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
/* Certain errors are in a single line; this makes them multi-line for better readability. */
|
||||
.wrapped-code-block-for-multi-line :global(pre),
|
||||
.wrapped-code-block-for-multi-line :global(code) {
|
||||
padding: unset;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,7 @@
|
||||
export let content = '';
|
||||
export let classes = '';
|
||||
|
||||
function getIntials(name: string) {
|
||||
function getInitials(name: string) {
|
||||
let words = name.split(' ');
|
||||
// If there is only one word, split it by underscore
|
||||
if (words.length === 1) {
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<div class="phone {classes}">
|
||||
<div class="avatar-initials u-text-center u-width-full-line u-line-height-1-5 u-medium u-bold">
|
||||
{getIntials($project.name)}
|
||||
{getInitials($project.name)}
|
||||
</div>
|
||||
<div class="project-name u-text-center u-x-small u-width-full-line">{$project.name}</div>
|
||||
<div class="chat u-text-center u-width-full-line">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
let time: string;
|
||||
let dateTime: Date;
|
||||
let docsUrl = `https://appwrite.io/docs/products/messaging`;
|
||||
let showConfimation = false;
|
||||
let showConfirmation = false;
|
||||
|
||||
let totalTargets = $messageParams[$providerType].targets?.length ?? 0;
|
||||
|
||||
@@ -60,14 +60,14 @@
|
||||
|
||||
async function askForConfirmation() {
|
||||
$wizard.interceptorNotificationEnabled = false;
|
||||
showConfimation = true;
|
||||
showConfirmation = true;
|
||||
throw 'Show confirmation';
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
$wizard.interceptorNotificationEnabled = true;
|
||||
await $wizard.finalAction();
|
||||
showConfimation = false;
|
||||
showConfirmation = false;
|
||||
}
|
||||
|
||||
$: if (when === 'now') {
|
||||
@@ -127,14 +127,14 @@
|
||||
</Helper>
|
||||
</WizardStep>
|
||||
|
||||
<Modal title="Send message" bind:show={showConfimation} headerDivider={false} onSubmit={submit}>
|
||||
<Modal title="Send message" bind:show={showConfirmation} headerDivider={false} onSubmit={submit}>
|
||||
<p>
|
||||
You are about to send a message to an estimated <span class="u-bold">{totalTargets}</span> recipients.
|
||||
Would you like to proceed?
|
||||
</p>
|
||||
<p class="u-bold">This action is irreversible.</p>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button text on:click={() => (showConfimation = false)}>Cancel</Button>
|
||||
<Button text on:click={() => (showConfirmation = false)}>Cancel</Button>
|
||||
<Button secondary submit>Send</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
@@ -16,7 +16,7 @@
|
||||
import { Container, type UsagePeriods } from '$lib/layout';
|
||||
import { onMount } from 'svelte';
|
||||
import { onboarding, project } from '../store';
|
||||
import Bandwith from './bandwith.svelte';
|
||||
import Bandwidth from './bandwidth.svelte';
|
||||
import { createApiKey } from './keys/+page.svelte';
|
||||
import Onboard from './onboard.svelte';
|
||||
import Realtime from './realtime.svelte';
|
||||
@@ -91,7 +91,7 @@
|
||||
<section class="common-section">
|
||||
<div class="grid-dashboard-1s-2m-6l">
|
||||
<div class="card is-2-columns-medium-screen is-3-columns-large-screen">
|
||||
<Bandwith {period} on:change={(e) => changePeriod(e.detail)} />
|
||||
<Bandwidth {period} on:change={(e) => changePeriod(e.detail)} />
|
||||
</div>
|
||||
<div class="card is-2-columns-medium-screen is-3-columns-large-screen">
|
||||
<Requests {period} on:change={(e) => changePeriod(e.detail)} />
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@
|
||||
value: number;
|
||||
}>;
|
||||
|
||||
$: bandwith = humanFileSize(totalMetrics($usage?.network));
|
||||
$: bandwidth = humanFileSize(totalMetrics($usage?.network));
|
||||
|
||||
$: if (period) {
|
||||
showPeriod = false;
|
||||
@@ -28,8 +28,8 @@
|
||||
<div class="u-flex u-gap-16 u-main-space-between">
|
||||
<div>
|
||||
<div class="heading-level-4">
|
||||
{bandwith.value}
|
||||
<span class="body-text-2">{bandwith.unit}</span>
|
||||
{bandwidth.value}
|
||||
<span class="body-text-2">{bandwidth.unit}</span>
|
||||
</div>
|
||||
<div>Bandwidth</div>
|
||||
</div>
|
||||
@@ -45,7 +45,7 @@
|
||||
</svelte:fragment>
|
||||
</DropList>
|
||||
</div>
|
||||
{#if bandwith.value !== '0'}
|
||||
{#if bandwidth.value !== '0'}
|
||||
<div style="height: 12rem;">
|
||||
<BarChart
|
||||
options={{
|
||||
+7
-2
@@ -3,15 +3,20 @@
|
||||
import Id from '$lib/components/id.svelte';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { isCloud } from '$lib/system';
|
||||
|
||||
const { endpoint, project } = sdk.forProject.client.config;
|
||||
const code = `import io.appwrite.Client
|
||||
import io.appwrite.services.Account
|
||||
|
||||
val client = Client(context)
|
||||
${
|
||||
isCloud
|
||||
? `val client = Client(context).setProject("${project}")`
|
||||
: `val client = Client(context)
|
||||
.setEndpoint("${endpoint}")
|
||||
.setProject("${project}")
|
||||
.setSelfSigned(status = true) // For self signed certificates, only use for development`;
|
||||
.setSelfSigned(status: true) // For self signed certificates, only use for development`
|
||||
}`;
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
|
||||
+11
-7
@@ -1,17 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { Alert, Code } from '$lib/components';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { isSelfHosted } from '$lib/system';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import Id from '$lib/components/id.svelte';
|
||||
|
||||
const { endpoint, project } = sdk.forProject.client.config;
|
||||
const code = `import Appwrite
|
||||
|
||||
let client = Client()
|
||||
${
|
||||
isCloud
|
||||
? `let client = Client().setProject("${project}")`
|
||||
: `let client = Client()
|
||||
.setEndpoint("${endpoint}")
|
||||
.setProject("${project}")
|
||||
.setSelfSigned(true) // For self signed certificates, only use for development`;
|
||||
.setSelfSigned(true) // For self signed certificates, only use for development`
|
||||
}`;
|
||||
|
||||
let showAlert = true;
|
||||
</script>
|
||||
@@ -21,16 +25,16 @@ let client = Client()
|
||||
|
||||
<h2 class="heading-level-7">Initialize your SDK</h2>
|
||||
<p>
|
||||
Initialize your SDK by pointing the client to your Appwrite project using your <Id
|
||||
value={project}>Project ID</Id
|
||||
>.
|
||||
Initialize your SDK by pointing the client to your Appwrite project using your
|
||||
<Id value={project}>Project ID</Id>
|
||||
.
|
||||
</p>
|
||||
<Code label="Apple SDK" labelIcon="apple" language="swift" {code} withCopy withLineNumbers />
|
||||
<p class="u-margin-block-start-24">
|
||||
Before sending any API calls to your new Appwrite project, make sure your device or emulator
|
||||
has network access to your Appwrite project's hostname or IP address.
|
||||
</p>
|
||||
{#if showAlert && isSelfHosted}
|
||||
{#if showAlert && !isCloud}
|
||||
<div class="common-section">
|
||||
<Alert type="info" dismissible on:dismiss={() => (showAlert = false)}>
|
||||
<svelte:fragment slot="title">For self-hosted solutions</svelte:fragment>
|
||||
|
||||
+10
-6
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Alert, Code } from '$lib/components';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { isSelfHosted } from '$lib/system';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import Id from '$lib/components/id.svelte';
|
||||
|
||||
@@ -9,10 +9,14 @@
|
||||
const code = `import 'package:appwrite/appwrite.dart';
|
||||
|
||||
Client client = Client();
|
||||
client
|
||||
${
|
||||
isCloud
|
||||
? `client.setProject('${project}');`
|
||||
: `client
|
||||
.setEndpoint('${endpoint}')
|
||||
.setProject('${project}')
|
||||
.setSelfSigned(status: true); // For self signed certificates, only use for development`;
|
||||
.setSelfSigned(status: true); // For self signed certificates, only use for development;`
|
||||
}`;
|
||||
|
||||
let showAlert = true;
|
||||
</script>
|
||||
@@ -22,8 +26,8 @@ client
|
||||
|
||||
<h2 class="heading-level-7">Initialize your SDK</h2>
|
||||
<p data-private>
|
||||
Initialize your SDK by pointing the client to your Appwrite project using your <Id
|
||||
value={project}>Project ID</Id>
|
||||
Initialize your SDK by pointing the client to your Appwrite project using your
|
||||
<Id value={project}>Project ID</Id>
|
||||
</p>
|
||||
<div class="u-margin-block-start-16">
|
||||
<Code
|
||||
@@ -39,7 +43,7 @@ client
|
||||
Before sending any API calls to your new Appwrite project, make sure your device or emulator
|
||||
has network access to your Appwrite project's hostname or IP address.
|
||||
</p>
|
||||
{#if showAlert && isSelfHosted}
|
||||
{#if showAlert && !isCloud}
|
||||
<div class="common-section">
|
||||
<Alert type="info" on:dismiss={() => (showAlert = false)}>
|
||||
<svelte:fragment slot="title">For self-hosted solutions</svelte:fragment>
|
||||
|
||||
+10
-6
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Alert, Code } from '$lib/components';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { isSelfHosted } from '$lib/system';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { createPlatform } from '../store';
|
||||
import Id from '$lib/components/id.svelte';
|
||||
@@ -9,11 +9,15 @@
|
||||
const { endpoint, project } = sdk.forProject.client.config;
|
||||
const code = `import { Client, Account, ID } from 'react-native-appwrite';
|
||||
|
||||
const client = new Client();
|
||||
const client
|
||||
.setEndpoint('${endpoint}')
|
||||
const client = new Client()${
|
||||
isCloud
|
||||
? ''
|
||||
: `
|
||||
.setEndpoint('${endpoint}')`
|
||||
}
|
||||
.setProject('${project}')
|
||||
.setPlatform('${$createPlatform.key}');`;
|
||||
.setPlatform('${$createPlatform.key}');
|
||||
`;
|
||||
|
||||
let showAlert = true;
|
||||
</script>
|
||||
@@ -40,7 +44,7 @@ const client
|
||||
Before sending any API calls to your new Appwrite project, make sure your device or emulator
|
||||
has network access to your Appwrite project's hostname or IP address.
|
||||
</p>
|
||||
{#if showAlert && isSelfHosted}
|
||||
{#if showAlert && !isCloud}
|
||||
<div class="common-section">
|
||||
<Alert type="info" on:dismiss={() => (showAlert = false)}>
|
||||
<svelte:fragment slot="title">For self-hosted solutions</svelte:fragment>
|
||||
|
||||
@@ -3,13 +3,17 @@
|
||||
import Id from '$lib/components/id.svelte';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { isCloud } from '$lib/system';
|
||||
|
||||
const { endpoint, project } = sdk.forProject.client.config;
|
||||
const code = `const client = new Client();
|
||||
|
||||
client
|
||||
${
|
||||
isCloud
|
||||
? `client.setProject('${project}');`
|
||||
: `client
|
||||
.setEndpoint('${endpoint}')
|
||||
.setProject('${project}');`;
|
||||
.setProject('${project}');`
|
||||
}`;
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import deepEqual from 'deep-equal';
|
||||
import { onMount } from 'svelte';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { SMTPSecure } from '@appwrite.io/console';
|
||||
import { type SMTPSecure } from '@appwrite.io/console';
|
||||
import InputSelect from '$lib/elements/forms/inputSelect.svelte';
|
||||
import { upgradeURL } from '$lib/stores/billing';
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
username = undefined;
|
||||
password = undefined;
|
||||
}
|
||||
|
||||
await sdk.forConsole.projects.updateSmtp(
|
||||
$project.$id,
|
||||
enabled,
|
||||
@@ -75,7 +76,7 @@
|
||||
port ? port : undefined,
|
||||
username ? username : undefined,
|
||||
password ? password : undefined,
|
||||
secure ? SMTPSecure.Tls : undefined
|
||||
secure ? (secure as SMTPSecure) : undefined
|
||||
);
|
||||
|
||||
invalidate(Dependencies.PROJECT);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
show = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `${$project.name} has been transfered to ${teamName}`
|
||||
message: `${$project.name} has been transferred to ${teamName}`
|
||||
});
|
||||
trackEvent(Submit.ProjectUpdateTeam);
|
||||
await goto(`${base}/organization-${teamId}`);
|
||||
|
||||
@@ -73,5 +73,5 @@
|
||||
</script>
|
||||
|
||||
<Wizard confirmExit title="Create Webhook" steps={stepsComponents} on:finish={create}>
|
||||
<svelte:fragment slot="exit">webhook creation</svelte:fragment>
|
||||
<svelte:fragment slot="exit">Are you sure you want to exit from this process?</svelte:fragment>
|
||||
</Wizard>
|
||||
@@ -231,7 +231,7 @@
|
||||
<svelte:window on:keydown={windowKeyDown} />
|
||||
|
||||
<div class="cb-card" class:active class:interacting style={styles} bind:this={cardEl}>
|
||||
<div class="card__translater">
|
||||
<div class="card__translator">
|
||||
<button
|
||||
class="card__rotator"
|
||||
aria-label="Expand the Card"
|
||||
@@ -320,12 +320,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.cb-card.active .card__translater,
|
||||
.cb-card.active .card__translator,
|
||||
.cb-card.active .card__rotator {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.card__translater,
|
||||
.card__translator,
|
||||
.card__rotator {
|
||||
display: grid;
|
||||
perspective: 600px;
|
||||
@@ -334,7 +334,7 @@
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.card__translater {
|
||||
.card__translator {
|
||||
width: auto;
|
||||
position: relative;
|
||||
transform: translate3d(var(--tx), var(--ty), 0) scale(var(--s));
|
||||
|
||||
Reference in new issue
Block a user