mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'dev-1.4.x' of github.com:appwrite/console into billing
This commit is contained in:
Generated
+9
-9
@@ -7,8 +7,8 @@
|
||||
"name": "@appwrite/console",
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "^0.3.0",
|
||||
"@appwrite.io/pink": "0.1.0",
|
||||
"@appwrite.io/pink-icons": "^0.1.0",
|
||||
"@appwrite.io/pink": "0.2.0",
|
||||
"@appwrite.io/pink-icons": "0.2.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/svelte": "^7.66.0",
|
||||
"@sentry/tracing": "^7.66.0",
|
||||
@@ -168,19 +168,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@appwrite.io/pink": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.1.0.tgz",
|
||||
"integrity": "sha512-z+4wiTH2PBMrbxvXiNjGQY0hs6ziCbKSb2rK0O/2M3aa9CHN/dBDSTpWCcED8G9BWDkeS5XMVZrQbyrdqMVc/Q==",
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.2.0.tgz",
|
||||
"integrity": "sha512-ni6O/yPiWkCYQ68PNcbmus6QrPpIEl7xmzKHU2dkV2L19RVio8thtBtT9ckJJ8uBMGsczASWs0fUqOxIvBmtNw==",
|
||||
"dependencies": {
|
||||
"@appwrite.io/pink-icons": "0.1.0",
|
||||
"@appwrite.io/pink-icons": "0.2.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"the-new-css-reset": "^1.11.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@appwrite.io/pink-icons": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/pink-icons/-/pink-icons-0.1.0.tgz",
|
||||
"integrity": "sha512-Y5DmvosdCoBD0oyqKV+ncbXTzQuhX0WOe4N7uonMaz1NaFm3ODaIb/CF77hV2vg86oOQ+f+BirdhfPsBue2pNA=="
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/pink-icons/-/pink-icons-0.2.0.tgz",
|
||||
"integrity": "sha512-wThBUGdvpwT0q2fcUapiugfBiB4RFDvTlW6p+U7Dol61mmCpNteFSIoBPiPJzN5015n1v4UEWL/rdOia4CWdBQ=="
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.23.4",
|
||||
|
||||
+2
-2
@@ -19,8 +19,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "^0.3.0",
|
||||
"@appwrite.io/pink": "0.1.0",
|
||||
"@appwrite.io/pink-icons": "^0.1.0",
|
||||
"@appwrite.io/pink": "0.2.0",
|
||||
"@appwrite.io/pink-icons": "0.2.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/svelte": "^7.66.0",
|
||||
"@sentry/tracing": "^7.66.0",
|
||||
|
||||
Generated
+7647
File diff suppressed because it is too large
Load Diff
@@ -143,7 +143,7 @@
|
||||
.drop-arrow::before {
|
||||
content: '';
|
||||
transform: rotate(45deg);
|
||||
background: hsl(var(--color-neutral-200));
|
||||
background: hsl(var(--color-neutral-85));
|
||||
|
||||
body.theme-light & {
|
||||
background: hsl(var(--color-neutral-10));
|
||||
|
||||
@@ -69,3 +69,5 @@ export { default as FloatingActionBar } from './floatingActionBar.svelte';
|
||||
export { default as LoadingDots } from './loadingDots.svelte';
|
||||
export { default as FakeModal } from './fakeModal.svelte';
|
||||
export { default as RadioBoxes } from './radioBoxes.svelte';
|
||||
export { default as ModalWrapper } from './modalWrapper.svelte';
|
||||
export { default as ModalSideCol } from './modalSideCol.svelte';
|
||||
|
||||
+66
-130
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
||||
import { Alert } from '$lib/components';
|
||||
import { Alert, ModalWrapper } from '$lib/components';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { Form } from '$lib/elements/forms';
|
||||
import { disableCommands } from '$lib/commandCenter';
|
||||
@@ -18,61 +17,8 @@
|
||||
export let title = '';
|
||||
export let description = '';
|
||||
|
||||
let dialog: HTMLDialogElement;
|
||||
let alert: HTMLElement;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
onMount(() => {
|
||||
if (show) openModal();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (show) closeModal();
|
||||
});
|
||||
|
||||
function handleBLur(event: MouseEvent) {
|
||||
if (event.target === dialog) {
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'backdrop'
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
function openModal() {
|
||||
if (dialog && !dialog.open) {
|
||||
dialog.showModal();
|
||||
document.documentElement.classList.add('u-overflow-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
if (closable) {
|
||||
if (dialog && dialog.open) {
|
||||
dispatch('close');
|
||||
dialog.close();
|
||||
show = false;
|
||||
document.documentElement.classList.remove('u-overflow-hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'escape'
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
|
||||
$: if (show) {
|
||||
openModal();
|
||||
} else {
|
||||
closeModal();
|
||||
}
|
||||
|
||||
$: $disableCommands(show);
|
||||
|
||||
$: if (error) {
|
||||
@@ -80,82 +26,72 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:mousedown={handleBLur} on:keydown={handleKeydown} />
|
||||
|
||||
<dialog
|
||||
class="modal"
|
||||
class:is-small={size === 'small'}
|
||||
class:is-big={size === 'big'}
|
||||
class:is-separate-header={headerDivider}
|
||||
bind:this={dialog}
|
||||
on:cancel|preventDefault>
|
||||
{#if show}
|
||||
<Form isModal {onSubmit}>
|
||||
<header class="modal-header">
|
||||
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
|
||||
<div class="u-flex u-cross-center u-gap-16">
|
||||
{#if icon}
|
||||
<div
|
||||
class="avatar is-medium"
|
||||
class:is-success={state === 'success'}
|
||||
class:is-warning={state === 'warning'}
|
||||
class:is-danger={state === 'error'}
|
||||
class:is-info={state === 'info'}>
|
||||
<span class={`icon-${icon}`} aria-hidden="true" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<h4 class="modal-title heading-level-5">
|
||||
<slot name="title">
|
||||
{title}
|
||||
</slot>
|
||||
</h4>
|
||||
</div>
|
||||
{#if closable}
|
||||
<button
|
||||
type="button"
|
||||
class="button is-text is-only-icon"
|
||||
style="--button-size:1.5rem;"
|
||||
aria-label="Close Modal"
|
||||
title="Close Modal"
|
||||
on:click={() =>
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'button'
|
||||
})}
|
||||
on:click={closeModal}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
<ModalWrapper bind:show {size} {headerDivider} let:close>
|
||||
<Form isModal {onSubmit}>
|
||||
<header class="modal-header">
|
||||
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
|
||||
<div class="u-flex u-cross-center u-gap-16">
|
||||
{#if icon}
|
||||
<div
|
||||
class="avatar is-medium"
|
||||
class:is-success={state === 'success'}
|
||||
class:is-warning={state === 'warning'}
|
||||
class:is-danger={state === 'error'}
|
||||
class:is-info={state === 'info'}>
|
||||
<span class={`icon-${icon}`} aria-hidden="true" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<p class="u-margin-block-start-4">
|
||||
<slot name="description">
|
||||
{description}
|
||||
</slot>
|
||||
</p>
|
||||
</header>
|
||||
<div class="modal-content">
|
||||
{#if error}
|
||||
<div bind:this={alert}>
|
||||
<Alert
|
||||
dismissible
|
||||
type="warning"
|
||||
on:dismiss={() => {
|
||||
error = null;
|
||||
}}>
|
||||
{error}
|
||||
</Alert>
|
||||
</div>
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
{#if $$slots.footer}
|
||||
<div class="modal-footer">
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
<h4 class="modal-title heading-level-5">
|
||||
<slot name="title">
|
||||
{title}
|
||||
</slot>
|
||||
</h4>
|
||||
</div>
|
||||
{#if closable}
|
||||
<button
|
||||
type="button"
|
||||
class="button is-text is-only-icon"
|
||||
style="--button-size:1.5rem;"
|
||||
aria-label="Close Modal"
|
||||
title="Close Modal"
|
||||
on:click={() =>
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'button'
|
||||
})}
|
||||
on:click={close}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<p class="u-margin-block-start-4">
|
||||
<slot name="description">
|
||||
{description}
|
||||
</slot>
|
||||
</p>
|
||||
</header>
|
||||
<div class="modal-content">
|
||||
{#if error}
|
||||
<div bind:this={alert}>
|
||||
<Alert
|
||||
dismissible
|
||||
type="warning"
|
||||
on:dismiss={() => {
|
||||
error = null;
|
||||
}}>
|
||||
{error}
|
||||
</Alert>
|
||||
</div>
|
||||
{/if}
|
||||
</Form>
|
||||
{/if}
|
||||
</dialog>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
{#if $$slots.footer}
|
||||
<div class="modal-footer">
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</Form>
|
||||
</ModalWrapper>
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<script lang="ts">
|
||||
import { ModalWrapper } from '$lib/components';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
export let show = false;
|
||||
export let title = '';
|
||||
export let description = '';
|
||||
export let style = '';
|
||||
</script>
|
||||
|
||||
<ModalWrapper bind:show let:close {style}>
|
||||
<div class="grid-1-1 u-width-full-line mk-grid">
|
||||
<div class="mk-grid-item-1 u-width-full-line">
|
||||
<slot name="side" />
|
||||
</div>
|
||||
<div class="u-padding-32 mk-grid-item-2">
|
||||
<header class="modal-header">
|
||||
<div class="u-flex u-main-space-between u-gap-16">
|
||||
<h4 class="modal-title heading-level-5">
|
||||
<slot name="title">
|
||||
{title}
|
||||
</slot>
|
||||
</h4>
|
||||
<button
|
||||
type="button"
|
||||
class="button is-text is-only-icon"
|
||||
style="--button-size:1.5rem;"
|
||||
aria-label="Close Modal"
|
||||
title="Close Modal"
|
||||
on:click={() =>
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'button'
|
||||
})}
|
||||
on:click={close}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
<p class="u-margin-block-start-4">
|
||||
<slot name="description">
|
||||
{description}
|
||||
</slot>
|
||||
</p>
|
||||
</header>
|
||||
<div class="modal-content">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
|
||||
<style lang="scss">
|
||||
.mk-grid {
|
||||
overflow: hidden;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.mk-grid {
|
||||
&-item-1 {
|
||||
order: 2;
|
||||
max-height: 16rem;
|
||||
}
|
||||
|
||||
&-item-2 {
|
||||
order: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,82 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { disableCommands } from '$lib/commandCenter';
|
||||
|
||||
export let show = false;
|
||||
export let size: 'small' | 'big' = null;
|
||||
export let closable = true;
|
||||
export let headerDivider = true;
|
||||
export let style = '';
|
||||
|
||||
let dialog: HTMLDialogElement;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
onMount(() => {
|
||||
if (show) openModal();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (show) closeModal();
|
||||
});
|
||||
|
||||
function handleBLur(event: MouseEvent) {
|
||||
if (event.target === dialog) {
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'backdrop'
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
function openModal() {
|
||||
if (dialog && !dialog.open) {
|
||||
dialog.showModal();
|
||||
document.documentElement.classList.add('u-overflow-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
if (closable) {
|
||||
if (dialog && dialog.open) {
|
||||
dispatch('close');
|
||||
dialog.close();
|
||||
show = false;
|
||||
document.documentElement.classList.remove('u-overflow-hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'escape'
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
|
||||
$: if (show) {
|
||||
openModal();
|
||||
} else {
|
||||
closeModal();
|
||||
}
|
||||
|
||||
$: $disableCommands(show);
|
||||
</script>
|
||||
|
||||
<svelte:window on:mousedown={handleBLur} on:keydown={handleKeydown} />
|
||||
|
||||
<dialog
|
||||
class="modal"
|
||||
class:is-small={size === 'small'}
|
||||
class:is-big={size === 'big'}
|
||||
class:is-separate-header={headerDivider}
|
||||
{style}
|
||||
bind:this={dialog}
|
||||
on:cancel|preventDefault>
|
||||
{#if show}
|
||||
<slot close={closeModal} />
|
||||
{/if}
|
||||
</dialog>
|
||||
@@ -93,25 +93,27 @@
|
||||
<div
|
||||
class="git-container u-position-relative"
|
||||
class:u-margin-block-start-24={isSelfHosted && !isVcsEnabled}>
|
||||
<div
|
||||
class:u-hide={!isSelfHosted || isVcsEnabled}
|
||||
class="overlay u-flex-vertical u-position-absolute u-height-100-percent u-width-full-line u-z-index-1 card u-text-center">
|
||||
{#if isSelfHosted && !isVcsEnabled}
|
||||
<div
|
||||
class="u-flex-vertical u-height-100-percent u-main-center u-cross-center u-gap-16">
|
||||
<Heading size="7" tag="h6"
|
||||
>Configure your self-hosted instance to connect to Git</Heading>
|
||||
<p>
|
||||
Connect your function to a Git repository or use a pre-made template<br />after
|
||||
configuring your self-hosted instance. Learn more in our
|
||||
<a
|
||||
href="https://appwrite.io/docs/advanced/self-hosting/functions#git"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link">documentation</a
|
||||
>.
|
||||
</p>
|
||||
class="overlay u-flex-vertical u-position-absolute u-height-100-percent u-width-full-line u-z-index-1 card u-text-center">
|
||||
<div
|
||||
class="u-flex-vertical u-height-100-percent u-main-center u-cross-center u-gap-16">
|
||||
<Heading size="7" tag="h6">
|
||||
Configure your self-hosted instance to connect to Git
|
||||
</Heading>
|
||||
<p>
|
||||
Connect your function to a Git repository or use a pre-made template<br />after
|
||||
configuring your self-hosted instance. Learn more in our
|
||||
<a
|
||||
href="https://appwrite.io/docs/advanced/self-hosting/functions#git"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link">documentation</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid-1-1 u-gap-24">
|
||||
<div class="card u-cross-child-start u-height-100-percent">
|
||||
<Heading size="6" tag="h6">Connect Git repository</Heading>
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<script lang="ts">
|
||||
import { Box, ModalSideCol } from '$lib/components';
|
||||
import SideLight from './side-light.png';
|
||||
import SideDark from './side-dark.png';
|
||||
import { app } from '$lib/stores/app';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
export let show = false;
|
||||
</script>
|
||||
|
||||
<ModalSideCol bind:show title="Get ready for Appwrite Pro" style="max-width: min(53rem,95%)">
|
||||
<svelte:fragment slot="side">
|
||||
{#if $app.themeInUse === 'dark'}
|
||||
<img
|
||||
src={SideDark}
|
||||
style="object-fit: cover; object-position: 30% 100%; height: 100%; width: 100%; aspect-ratio: 1 / 1;"
|
||||
alt="appwrite pro"
|
||||
aria-hidden="true"
|
||||
width="376" />
|
||||
{:else}
|
||||
<img
|
||||
src={SideLight}
|
||||
style="object-fit: cover; object-position: 30% 100%; height: 100%; width: 100%; aspect-ratio: 1 / 1;"
|
||||
alt="appwrite pro"
|
||||
aria-hidden="true"
|
||||
width="376" />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
<div class="u-flex u-flex-vertical u-gap-16">
|
||||
<p class="text">
|
||||
Appwrite will enable billing before the end of the year, which means access to our long
|
||||
awaited Pro plan. It also means you will be limited to <b
|
||||
>one free organization per account</b
|
||||
>.
|
||||
</p>
|
||||
<p class="text">
|
||||
Consider upgrading and take advantage of the extra resources that come with the Pro
|
||||
plan. You can also use our Migrations service to self-host some of your projects
|
||||
instead. Learn more in our <a
|
||||
class="link"
|
||||
href="https://appwrite.io/docs/advanced/migrations"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
on:click={() =>
|
||||
trackEvent('click_open_website', {
|
||||
source: 'pre_billing_release_modal',
|
||||
destination: 'docs_migration'
|
||||
})}>documentation</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
<Box>
|
||||
<b class="body-text-1">Pro - $15 per member per billing period</b>
|
||||
|
||||
<ul class="list u-flex-vertical u-gap-8 u-margin-block-start-24">
|
||||
<li class="u-flex u-gap-8 u-cross-center">
|
||||
<span class="icon-check-circle" aria-hidden="true" />
|
||||
<span class="text">Unlimited org. members</span>
|
||||
</li>
|
||||
<li class="u-flex u-gap-8 u-cross-center">
|
||||
<span class="icon-check-circle" aria-hidden="true" />
|
||||
<span class="text">300GB bandwidth</span>
|
||||
</li>
|
||||
<li class="u-flex u-gap-8 u-cross-center">
|
||||
<span class="icon-check-circle" aria-hidden="true" />
|
||||
<span class="text">200,000 monthly active users</span>
|
||||
</li>
|
||||
<li class="u-flex u-gap-8 u-cross-center">
|
||||
<span class="icon-check-circle" aria-hidden="true" />
|
||||
<span class="text">Email support</span>
|
||||
</li>
|
||||
<li class="u-flex u-gap-8 u-cross-center">
|
||||
<span class="icon-check-circle" aria-hidden="true" />
|
||||
<span class="text">And more</span>
|
||||
</li>
|
||||
</ul>
|
||||
<Button
|
||||
fullWidth
|
||||
class="u-margin-block-start-24"
|
||||
href="https://appwrite.io/pricing"
|
||||
on:click={() =>
|
||||
trackEvent('click_open_website', {
|
||||
source: 'pre_billing_release_modal',
|
||||
destination: 'pricing'
|
||||
})}>
|
||||
Learn more about Pro
|
||||
</Button>
|
||||
</Box>
|
||||
</ModalSideCol>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 619 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 507 KiB |
@@ -22,9 +22,7 @@
|
||||
} from '$lib/stores/billing';
|
||||
import { diffDays, toLocaleDate } from '$lib/helpers/date';
|
||||
import { base } from '$app/paths';
|
||||
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
import { CommandCenter, registerCommands, registerSearchers } from '$lib/commandCenter';
|
||||
import { AIPanel, OrganizationsPanel, ProjectsPanel } from '$lib/commandCenter/panels';
|
||||
import { orgSearcher, projectsSearcher } from '$lib/commandCenter/searchers';
|
||||
@@ -33,7 +31,6 @@
|
||||
import { openMigrationWizard } from './(migration-wizard)';
|
||||
import { project } from './project-[project]/store';
|
||||
import { feedback } from '$lib/stores/feedback';
|
||||
import { consoleVariables } from './store';
|
||||
import { VARS, hasStripePublicKey, isCloud } from '$lib/system';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { loadStripe } from '@stripe/stripe-js';
|
||||
@@ -44,6 +41,8 @@
|
||||
import { showExcess } from './organization-[organization]/store';
|
||||
import UsageRates from './wizard/cloudOrganization/usageRates.svelte';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { consoleVariables, showPrereleaseModal } from './store';
|
||||
import PreReleaseModal from './(billing-modal)/preReleaseModal.svelte';
|
||||
|
||||
function kebabToSentenceCase(str: string) {
|
||||
return str
|
||||
@@ -243,6 +242,10 @@
|
||||
|
||||
onMount(async () => {
|
||||
loading.set(false);
|
||||
if (isCloud && !$page.url.pathname.includes('/console/onboarding')) {
|
||||
checkForPreReleaseProModal();
|
||||
}
|
||||
|
||||
setInterval(() => {
|
||||
checkForFeedback(INTERVAL);
|
||||
}, INTERVAL);
|
||||
@@ -374,6 +377,47 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
function checkForPreReleaseProModal() {
|
||||
const modalTime = localStorage.getItem('preReleaseProModal');
|
||||
const notificationTime = localStorage.getItem('preReleaseProNotification');
|
||||
const now = Date.now();
|
||||
// show the modal if it was never shown
|
||||
if (!modalTime) {
|
||||
localStorage.setItem('preReleaseProModal', Date.now().toString());
|
||||
localStorage.setItem('preReleaseProNotification', Date.now().toString());
|
||||
showPrereleaseModal.set(true);
|
||||
} else {
|
||||
const interval = 5 * 24 * 60 * 60 * 1000;
|
||||
const sinceLastModal = now - parseInt(modalTime);
|
||||
// show the modal if it was shown more than 5 days ago
|
||||
if (sinceLastModal > interval) {
|
||||
localStorage.setItem('preReleaseProModal', Date.now().toString());
|
||||
localStorage.setItem('preReleaseProNotification', Date.now().toString());
|
||||
showPrereleaseModal.set(true);
|
||||
}
|
||||
//if the modal has been shown more than 24 ago and the notification has not been shown for 24 hours
|
||||
else if (
|
||||
sinceLastModal > 24 * 60 * 60 * 1000 &&
|
||||
now - (notificationTime ? parseInt(notificationTime) : 0) > 24 * 60 * 60 * 1000
|
||||
) {
|
||||
localStorage.setItem('preReleaseProNotification', Date.now().toString());
|
||||
addNotification({
|
||||
type: 'warning',
|
||||
timeout: 10000,
|
||||
message:
|
||||
'Appwrite Pro is coming soon, which means you will be limited to one free organization per account. To avoid service disruptions in your projects, consider upgrading to Pro.',
|
||||
buttons: [
|
||||
{
|
||||
name: 'Learn more',
|
||||
method: () => {
|
||||
window.open('https://appwrite.io/pricing', '_blank');
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$: if (!$log.show) {
|
||||
$log.data = null;
|
||||
@@ -457,3 +501,6 @@
|
||||
{#if isCloud && $showUsageRatesModal}
|
||||
<UsageRates bind:show={$showUsageRatesModal} tier={$organization?.billingPlan} />
|
||||
{/if}
|
||||
{#if isCloud && $showPrereleaseModal && !$page.url.pathname.includes('/console/onboarding')}
|
||||
<PreReleaseModal bind:show={$showPrereleaseModal} />
|
||||
{/if}
|
||||
|
||||
@@ -177,6 +177,13 @@
|
||||
<style lang="scss">
|
||||
@import '@appwrite.io/pink/src/abstract/variables/_devices.scss';
|
||||
|
||||
.card {
|
||||
background: #fbfbfc;
|
||||
|
||||
:global(.theme-dark) & {
|
||||
background: #19191c !important;
|
||||
}
|
||||
}
|
||||
@media #{$break2open} {
|
||||
.card-header {
|
||||
background-image: var(--url);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { page } from '$app/stores';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { derived } from 'svelte/store';
|
||||
import { derived, writable } from 'svelte/store';
|
||||
|
||||
export const version = derived(page, ($page) => $page.data.version as string | null);
|
||||
export const consoleVariables = derived(
|
||||
page,
|
||||
($page) => $page.data.consoleVariables as Models.ConsoleVariables
|
||||
);
|
||||
|
||||
export const showPrereleaseModal = writable(false);
|
||||
|
||||
Reference in New Issue
Block a user