mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge remote-tracking branch 'origin/main' into poc-invoice-cycle-ref
This commit is contained in:
@@ -17,8 +17,8 @@ jobs:
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
@@ -54,8 +54,8 @@ jobs:
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
@@ -90,8 +90,8 @@ jobs:
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
"e2e:ui": "playwright test tests/e2e --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "1.4.6",
|
||||
"@appwrite.io/console": "1.4.7",
|
||||
"@appwrite.io/pink": "0.25.0",
|
||||
"@appwrite.io/pink-icons": "0.25.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
|
||||
Generated
+7
-7
@@ -9,8 +9,8 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@appwrite.io/console':
|
||||
specifier: 1.4.6
|
||||
version: 1.4.6
|
||||
specifier: 1.4.7
|
||||
version: 1.4.7
|
||||
'@appwrite.io/pink':
|
||||
specifier: 0.25.0
|
||||
version: 0.25.0
|
||||
@@ -95,7 +95,7 @@ importers:
|
||||
version: 6.6.3
|
||||
'@testing-library/svelte':
|
||||
specifier: ^5.2.4
|
||||
version: 5.2.4(svelte@4.2.19)(vite@5.4.11(@types/node@22.9.0)(sass@1.81.0))(vitest@1.6.0)
|
||||
version: 5.2.4(svelte@4.2.19)(vite@5.4.11(@types/node@22.9.0)(sass@1.81.0))(vitest@1.6.0(@types/node@22.9.0)(@vitest/ui@1.6.0)(jsdom@22.1.0)(sass@1.81.0))
|
||||
'@testing-library/user-event':
|
||||
specifier: ^14.5.2
|
||||
version: 14.5.2(@testing-library/dom@10.4.0)
|
||||
@@ -199,8 +199,8 @@ packages:
|
||||
'@analytics/type-utils@0.6.2':
|
||||
resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==}
|
||||
|
||||
'@appwrite.io/console@1.4.6':
|
||||
resolution: {integrity: sha512-oGA5gkecpy9E/fKJkaGn26JP9mgknc2Vn8hS6xhRBhmUPg8Vqlz0vgPpx1EQbPB2C5HWIf4yToSicOH31XGx6Q==}
|
||||
'@appwrite.io/console@1.4.7':
|
||||
resolution: {integrity: sha512-5zx+c5nWRm/UJNxgtOi4vj1pYW+wusfnOX2hqEGDLLuNZRc1rViYRefNuezosp5SPtjClCIYn9TGuFlz/XLwhw==}
|
||||
|
||||
'@appwrite.io/pink-icons@0.25.0':
|
||||
resolution: {integrity: sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q==}
|
||||
@@ -3834,7 +3834,7 @@ snapshots:
|
||||
|
||||
'@analytics/type-utils@0.6.2': {}
|
||||
|
||||
'@appwrite.io/console@1.4.6': {}
|
||||
'@appwrite.io/console@1.4.7': {}
|
||||
|
||||
'@appwrite.io/pink-icons@0.25.0': {}
|
||||
|
||||
@@ -5075,7 +5075,7 @@ snapshots:
|
||||
lodash: 4.17.21
|
||||
redent: 3.0.0
|
||||
|
||||
'@testing-library/svelte@5.2.4(svelte@4.2.19)(vite@5.4.11(@types/node@22.9.0)(sass@1.81.0))(vitest@1.6.0)':
|
||||
'@testing-library/svelte@5.2.4(svelte@4.2.19)(vite@5.4.11(@types/node@22.9.0)(sass@1.81.0))(vitest@1.6.0(@types/node@22.9.0)(@vitest/ui@1.6.0)(jsdom@22.1.0)(sass@1.81.0))':
|
||||
dependencies:
|
||||
'@testing-library/dom': 10.4.0
|
||||
svelte: 4.2.19
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { formatNum } from '$lib/helpers/string';
|
||||
import { plansInfo, tierFree, tierPro, type Tier } from '$lib/stores/billing';
|
||||
import { plansInfo, tierFree, tierPro, tierScale, type Tier } from '$lib/stores/billing';
|
||||
import { Card, SecondaryTabs, SecondaryTabsItem } from '..';
|
||||
|
||||
let selectedTab: Tier = BillingPlan.FREE;
|
||||
@@ -23,11 +23,11 @@
|
||||
on:click={() => (selectedTab = BillingPlan.PRO)}>
|
||||
{tierPro.name}
|
||||
</SecondaryTabsItem>
|
||||
<!-- <SecondaryTabsItem
|
||||
<SecondaryTabsItem
|
||||
disabled={selectedTab === BillingPlan.SCALE}
|
||||
on:click={() => (selectedTab = BillingPlan.SCALE)}>
|
||||
{tierScale.name}
|
||||
</SecondaryTabsItem> -->
|
||||
</SecondaryTabsItem>
|
||||
</SecondaryTabs>
|
||||
</div>
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
<p class="u-margin-block-start-8">Everything in the Pro plan, plus:</p>
|
||||
<ul class="un-order-list u-margin-inline-start-4">
|
||||
<li>Unlimited seats</li>
|
||||
<li>Organization roles <span class="inline-tag">Coming soon</span></li>
|
||||
<li>Organization roles</li>
|
||||
<li>SOC-2, HIPAA compliance</li>
|
||||
<li>SSO <span class="inline-tag">Coming soon</span></li>
|
||||
<li>Priority support</li>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
export function getFlag(country: string, width: number, height: number, quality: number) {
|
||||
if (!isValueOfStringEnum(Flag, country)) return '';
|
||||
let flag = sdk.forProject.avatars
|
||||
let flag = sdk.forConsole.avatars
|
||||
.getFlag(country, width * 2, height * 2, quality)
|
||||
?.toString();
|
||||
flag?.includes('&project=')
|
||||
|
||||
@@ -4,10 +4,21 @@ import { base } from '$app/paths';
|
||||
export function checkPricingRefAndRedirect(searchParams: URLSearchParams, shouldRegister = false) {
|
||||
if (searchParams.has('type')) {
|
||||
const paramType = searchParams.get('type');
|
||||
const hasPlan = searchParams.has('plan');
|
||||
if (paramType === 'create') {
|
||||
shouldRegister
|
||||
? goto(
|
||||
`${base}/register?type=create${hasPlan ? `&plan=${searchParams.get('plan')}` : ''}`
|
||||
)
|
||||
: goto(
|
||||
`${base}/create-organization?type=create${hasPlan ? `&plan=${searchParams.get('plan')}` : ''}`
|
||||
);
|
||||
}
|
||||
//Legacy
|
||||
if (paramType === 'createPro') {
|
||||
shouldRegister
|
||||
? goto(`${base}/register?type=createPro`)
|
||||
: goto(`${base}/create-organization?type=createPro`);
|
||||
? goto(`${base}/register?type=create&plan=tier-1`)
|
||||
: goto(`${base}/create-organization?type=create&plan=tier-1`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
<Pill button on:click={() => (showDropdown = !showDropdown)}>
|
||||
<span class="icon-info" />{total}/{limit} created
|
||||
</Pill>
|
||||
{:else}
|
||||
{:else if $organization?.billingPlan !== BillingPlan.SCALE}
|
||||
<Pill button on:click={() => (showDropdown = !showDropdown)}>
|
||||
<span class="icon-info" />Limits applied
|
||||
</Pill>
|
||||
|
||||
@@ -175,7 +175,7 @@ export type TierData = {
|
||||
|
||||
export const tierFree: TierData = {
|
||||
name: 'Free',
|
||||
description: 'For personal hobby projects of small scale and students.'
|
||||
description: 'A great fit for passion projects and small applications.'
|
||||
};
|
||||
|
||||
export const tierGitHubEducation: TierData = {
|
||||
@@ -185,11 +185,13 @@ export const tierGitHubEducation: TierData = {
|
||||
|
||||
export const tierPro: TierData = {
|
||||
name: 'Pro',
|
||||
description: 'For pro developers and production projects that need the ability to scale.'
|
||||
description:
|
||||
'For production applications that need powerful functionality and resources to scale.'
|
||||
};
|
||||
export const tierScale: TierData = {
|
||||
name: 'Scale',
|
||||
description: 'For scaling teams and agencies that need dedicated support.'
|
||||
description:
|
||||
'For teams that handle more complex and large projects and need more control and support.'
|
||||
};
|
||||
|
||||
export const tierCustom: TierData = {
|
||||
|
||||
@@ -61,8 +61,7 @@ function createPreferences() {
|
||||
|
||||
getCustomCollectionColumns: (collectionId: string): Preferences['columns'] => {
|
||||
return (
|
||||
preferences[sdk.forProject.client.config.project]?.collections?.[collectionId] ??
|
||||
null
|
||||
preferences[sdk.forProject.client.config.project]?.collections?.[collectionId] ?? []
|
||||
);
|
||||
},
|
||||
setLimit: (limit: Preferences['limit']) =>
|
||||
|
||||
@@ -33,11 +33,11 @@
|
||||
{
|
||||
value: BillingPlan.PRO,
|
||||
label: `${tierToPlan(BillingPlan.PRO).name} - ${formatCurrency($plansInfo.get(BillingPlan.PRO).price)} / month + add-ons`
|
||||
},
|
||||
{
|
||||
value: BillingPlan.SCALE,
|
||||
label: `${tierToPlan(BillingPlan.SCALE).name} - ${formatCurrency($plansInfo.get(BillingPlan.SCALE).price)}/month + usage`
|
||||
}
|
||||
// {
|
||||
// value: BillingPlan.SCALE,
|
||||
// label: `${tierToPlan(BillingPlan.SCALE).name} - ${formatCurrency($plansInfo.get(BillingPlan.SCALE).price)}/month + usage`
|
||||
// }
|
||||
]
|
||||
: [];
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { selectedInvoice, showRetryModal } from './store';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
|
||||
let showDropdown = [];
|
||||
let showFailedError = false;
|
||||
// let isLoadingInvoices = true;
|
||||
|
||||
let offset = 0;
|
||||
let invoiceList: InvoiceList = {
|
||||
@@ -46,11 +46,13 @@
|
||||
onMount(request);
|
||||
|
||||
async function request() {
|
||||
// isLoadingInvoices = true;
|
||||
invoiceList = await sdk.forConsole.billing.listInvoices($page.params.organization, [
|
||||
Query.limit(limit),
|
||||
Query.offset(offset),
|
||||
Query.orderDesc('$createdAt')
|
||||
]);
|
||||
// isLoadingInvoices = false;
|
||||
}
|
||||
|
||||
function retryPayment(invoice: Invoice) {
|
||||
@@ -62,144 +64,151 @@
|
||||
request();
|
||||
}
|
||||
</script>
|
||||
{#if $organization?.billingPlan !== BillingPlan.FREE && invoiceList.total > 0}
|
||||
<CardGrid>
|
||||
<Heading tag="h2" size="6">Payment history</Heading>
|
||||
|
||||
<p class="text">
|
||||
Transaction history for this organization. Download invoices for more details about your
|
||||
payments.
|
||||
</p>
|
||||
<svelte:fragment slot="aside">
|
||||
{#if invoiceList.total > 0}
|
||||
<TableScroll noMargin transparent noStyles>
|
||||
<TableHeader>
|
||||
<TableCellHead width={100}>Due Date</TableCellHead>
|
||||
<TableCellHead width={80}>Status</TableCellHead>
|
||||
<TableCellHead width={100}>Amount Due</TableCellHead>
|
||||
<TableCellHead width={40} />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each invoiceList?.invoices as invoice, i}
|
||||
{@const status = invoice.status}
|
||||
<TableRow>
|
||||
<TableCellText title="date">
|
||||
{toLocaleDate(invoice.dueAt)}
|
||||
</TableCellText>
|
||||
<TableCell title="status">
|
||||
{#if invoice?.lastError}
|
||||
<DropList bind:show={showFailedError}>
|
||||
<Pill
|
||||
danger={status === 'overdue' ||
|
||||
status === 'failed' ||
|
||||
status === 'requires_authentication'}
|
||||
success={status === 'paid' ||
|
||||
status === 'succeeded'}
|
||||
warning={status === 'pending'}
|
||||
on:click={() => (showFailedError = true)}
|
||||
button>
|
||||
{status === 'requires_authentication'
|
||||
? 'failed'
|
||||
: status}
|
||||
</Pill>
|
||||
<svelte:fragment slot="list">
|
||||
<li>
|
||||
The scheduled payment has failed.
|
||||
<Button
|
||||
link
|
||||
on:click={() => {
|
||||
retryPayment(invoice);
|
||||
showFailedError = false;
|
||||
}}
|
||||
>Try again
|
||||
</Button>
|
||||
.
|
||||
</li>
|
||||
</svelte:fragment>
|
||||
</DropList>
|
||||
{:else}
|
||||
<CardGrid>
|
||||
<Heading tag="h2" size="6">Payment history</Heading>
|
||||
|
||||
<p class="text">
|
||||
Transaction history for this organization. Download invoices for more details about your
|
||||
payments.
|
||||
</p>
|
||||
<svelte:fragment slot="aside">
|
||||
{#if invoiceList.total > 0}
|
||||
<TableScroll noMargin transparent noStyles>
|
||||
<TableHeader>
|
||||
<TableCellHead width={100}>Due Date</TableCellHead>
|
||||
<TableCellHead width={80}>Status</TableCellHead>
|
||||
<TableCellHead width={100}>Amount Due</TableCellHead>
|
||||
<TableCellHead width={40} />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each invoiceList?.invoices as invoice, i}
|
||||
{@const status = invoice.status}
|
||||
<TableRow>
|
||||
<TableCellText title="date">
|
||||
{toLocaleDate(invoice.dueAt)}
|
||||
</TableCellText>
|
||||
<TableCell title="status">
|
||||
{#if invoice?.lastError}
|
||||
<DropList bind:show={showFailedError}>
|
||||
<Pill
|
||||
danger={status === 'overdue' ||
|
||||
status === 'failed' ||
|
||||
status === 'requires_authentication'}
|
||||
success={status === 'paid' || status === 'succeeded'}
|
||||
warning={status === 'pending'}>
|
||||
warning={status === 'pending'}
|
||||
on:click={() => (showFailedError = true)}
|
||||
button>
|
||||
{status === 'requires_authentication'
|
||||
? 'failed'
|
||||
: status}
|
||||
</Pill>
|
||||
{/if}
|
||||
</TableCell>
|
||||
<TableCellText title="due">
|
||||
{formatCurrency(invoice.grossAmount)}
|
||||
</TableCellText>
|
||||
<TableCell showOverflow right>
|
||||
<DropList
|
||||
bind:show={showDropdown[i]}
|
||||
placement="bottom-start"
|
||||
noArrow>
|
||||
<Button
|
||||
round
|
||||
text
|
||||
noMargin
|
||||
ariaLabel="More options"
|
||||
on:click={() => {
|
||||
showDropdown[i] = !showDropdown[i];
|
||||
}}>
|
||||
<span class="icon-dots-horizontal" aria-hidden="true" />
|
||||
</Button>
|
||||
<svelte:fragment slot="list">
|
||||
<DropListLink
|
||||
icon="external-link"
|
||||
external
|
||||
href={`${endpoint}/organizations/${$page.params.organization}/invoices/${invoice.$id}/view`}
|
||||
on:click={() =>
|
||||
(showDropdown[i] = !showDropdown[i])}
|
||||
event="view_invoice">
|
||||
View invoice
|
||||
</DropListLink>
|
||||
<DropListLink
|
||||
icon="download"
|
||||
href={`${endpoint}/organizations/${$page.params.organization}/invoices/${invoice.$id}/download`}
|
||||
on:click={() => {
|
||||
showDropdown[i] = !showDropdown[i];
|
||||
}}
|
||||
event="download_invoice">
|
||||
Download PDF
|
||||
</DropListLink>
|
||||
{#if status === 'overdue' || status === 'failed'}
|
||||
<DropListItem
|
||||
icon="refresh"
|
||||
<li>
|
||||
The scheduled payment has failed.
|
||||
<Button
|
||||
link
|
||||
on:click={() => {
|
||||
retryPayment(invoice);
|
||||
showDropdown[i] = !showDropdown[i];
|
||||
trackEvent(`click_retry_payment`, {
|
||||
from: 'button',
|
||||
source: 'billing_invoice_menu'
|
||||
});
|
||||
}}>
|
||||
Retry payment
|
||||
</DropListItem>
|
||||
{/if}
|
||||
showFailedError = false;
|
||||
}}
|
||||
>Try again
|
||||
</Button>
|
||||
.
|
||||
</li>
|
||||
</svelte:fragment>
|
||||
</DropList>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</TableScroll>
|
||||
<div class="u-flex u-main-space-between">
|
||||
<p class="text">Total results: {invoiceList?.total ?? 0}</p>
|
||||
<PaginationInline {limit} bind:offset sum={invoiceList?.total ?? 0} hidePages />
|
||||
</div>
|
||||
{:else}
|
||||
<EmptySearch hidePagination>
|
||||
<p class="text u-text-center">
|
||||
You have no payment history. After you receive your first invoice, you'll
|
||||
see it here.
|
||||
</p>
|
||||
</EmptySearch>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
{/if}
|
||||
{:else}
|
||||
<Pill
|
||||
danger={status === 'overdue' ||
|
||||
status === 'failed' ||
|
||||
status === 'requires_authentication'}
|
||||
success={status === 'paid' || status === 'succeeded'}
|
||||
warning={status === 'pending'}>
|
||||
{status === 'requires_authentication' ? 'failed' : status}
|
||||
</Pill>
|
||||
{/if}
|
||||
</TableCell>
|
||||
<TableCellText title="due">
|
||||
{formatCurrency(invoice.grossAmount)}
|
||||
</TableCellText>
|
||||
<TableCell showOverflow right>
|
||||
<DropList
|
||||
bind:show={showDropdown[i]}
|
||||
placement="bottom-start"
|
||||
noArrow>
|
||||
<Button
|
||||
round
|
||||
text
|
||||
noMargin
|
||||
ariaLabel="More options"
|
||||
on:click={() => {
|
||||
showDropdown[i] = !showDropdown[i];
|
||||
}}>
|
||||
<span class="icon-dots-horizontal" aria-hidden="true" />
|
||||
</Button>
|
||||
<svelte:fragment slot="list">
|
||||
<DropListLink
|
||||
icon="external-link"
|
||||
external
|
||||
href={`${endpoint}/organizations/${$page.params.organization}/invoices/${invoice.$id}/view`}
|
||||
on:click={() => (showDropdown[i] = !showDropdown[i])}
|
||||
event="view_invoice">
|
||||
View invoice
|
||||
</DropListLink>
|
||||
<DropListLink
|
||||
icon="download"
|
||||
href={`${endpoint}/organizations/${$page.params.organization}/invoices/${invoice.$id}/download`}
|
||||
on:click={() => {
|
||||
showDropdown[i] = !showDropdown[i];
|
||||
}}
|
||||
event="download_invoice">
|
||||
Download PDF
|
||||
</DropListLink>
|
||||
{#if status === 'overdue' || status === 'failed'}
|
||||
<DropListItem
|
||||
icon="refresh"
|
||||
on:click={() => {
|
||||
retryPayment(invoice);
|
||||
showDropdown[i] = !showDropdown[i];
|
||||
trackEvent(`click_retry_payment`, {
|
||||
from: 'button',
|
||||
source: 'billing_invoice_menu'
|
||||
});
|
||||
}}>
|
||||
Retry payment
|
||||
</DropListItem>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</DropList>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</TableScroll>
|
||||
<div class="u-flex u-main-space-between">
|
||||
<p class="text">Total results: {invoiceList.total}</p>
|
||||
<PaginationInline {limit} bind:offset sum={invoiceList.total} hidePages />
|
||||
</div>
|
||||
<!--{:else if isLoadingInvoices}-->
|
||||
<!-- <div class="loader-holder">-->
|
||||
<!-- <div class="loader" />-->
|
||||
<!-- </div>-->
|
||||
{:else}
|
||||
<EmptySearch hidePagination>
|
||||
<p class="text u-text-center">
|
||||
You have no payment history. After you receive your first invoice, you'll see it
|
||||
here.
|
||||
</p>
|
||||
</EmptySearch>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<!--<style>-->
|
||||
<!-- .loader-holder {-->
|
||||
<!-- height: 100%;-->
|
||||
<!-- align-content: center;-->
|
||||
<!-- justify-items: center;-->
|
||||
<!-- }-->
|
||||
<!--</style>-->
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
tier={BillingPlan.FREE}
|
||||
class="u-margin-block-start-24"
|
||||
members={data?.members?.total ?? 0} />
|
||||
{:else if billingPlan === BillingPlan.PRO && $organization.billingPlan === BillingPlan.SCALE}
|
||||
{:else if billingPlan === BillingPlan.PRO && $organization.billingPlan === BillingPlan.SCALE && collaborators?.length > 0}
|
||||
{@const extraMembers = collaborators?.length ?? 0}
|
||||
<Alert type="error" class="u-margin-block-start-24">
|
||||
<svelte:fragment slot="title">
|
||||
@@ -339,7 +339,7 @@
|
||||
id="couponId" />
|
||||
</FormList>
|
||||
{/if}
|
||||
{#if isDowngrade}
|
||||
{#if isDowngrade && billingPlan === BillingPlan.FREE}
|
||||
<FormList class="u-margin-block-start-24">
|
||||
<InputSelect
|
||||
id="reason"
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@
|
||||
<TableCellHead width={192}>Backups</TableCellHead>
|
||||
<TableCellHead width={80}>Size</TableCellHead>
|
||||
<TableCellHead width={120}>Status</TableCellHead>
|
||||
<TableCellHead width={80}>Policy</TableCellHead>
|
||||
<TableCellHead width={120}>Policy</TableCellHead>
|
||||
<TableCellHead width={48} />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
|
||||
+3
-1
@@ -92,7 +92,9 @@
|
||||
);
|
||||
return collections;
|
||||
} else {
|
||||
const collections = await sdk.forProject.databases.listCollections(databaseId);
|
||||
const collections = await sdk.forProject.databases.listCollections(databaseId, [
|
||||
Query.limit(100)
|
||||
]);
|
||||
return collections;
|
||||
}
|
||||
}
|
||||
|
||||
+15
-20
@@ -1,43 +1,37 @@
|
||||
<script lang="ts">
|
||||
import { Alert, CustomId } from '$lib/components';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { page } from '$app/stores';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { Button, FormList, InputFile } from '$lib/elements/forms';
|
||||
import { FormList, InputFile } from '$lib/elements/forms';
|
||||
import { humanFileSize, sizeToBytes } from '$lib/helpers/sizeConvertion';
|
||||
import WizardStep from '$lib/layout/wizardStep.svelte';
|
||||
import { tierToPlan, upgradeURL } from '$lib/stores/billing';
|
||||
import { organization, currentPlan } from '$lib/stores/organization';
|
||||
import { currentPlan } from '$lib/stores/organization';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { bucket } from '../store';
|
||||
import { createFile } from './store';
|
||||
import { base } from '$app/paths';
|
||||
|
||||
let showCustomId = false;
|
||||
let fileError: string = null;
|
||||
const service = $currentPlan['fileSize'];
|
||||
const projectId = $page.params.project;
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
<svelte:fragment slot="title">File</svelte:fragment>
|
||||
<svelte:fragment slot="subtitle">Upload a file to add it to your bucket.</svelte:fragment>
|
||||
|
||||
{#if isCloud}
|
||||
{@const size = humanFileSize(sizeToBytes(service, 'MB', 1000))}
|
||||
{@const plan = tierToPlan($organization?.billingPlan)}
|
||||
{#if isCloud && fileError === 'File size exceeds the limit'}
|
||||
{@const size = humanFileSize($bucket.maximumFileSize ?? sizeToBytes(service, 'MB', 1000))}
|
||||
<Alert type="info">
|
||||
<p class="text">
|
||||
The {plan.name} plan has a maximum upload file size limit of {Math.floor(
|
||||
parseInt(size.value)
|
||||
)}{size.unit}.
|
||||
{#if $organization?.billingPlan === BillingPlan.FREE}
|
||||
Upgrade to allow files of a larger size.
|
||||
{/if}
|
||||
The maximum file upload size for this bucket is {parseInt(size.value)}{size.unit}.
|
||||
You can adjust it in your
|
||||
<a
|
||||
href={`${base}/project-${projectId}/storage/bucket-${$bucket.$id}/settings`}
|
||||
style:text-decoration="underline">bucket settings</a
|
||||
>.
|
||||
</p>
|
||||
<svelte:fragment slot="action">
|
||||
{#if $organization?.billingPlan === BillingPlan.FREE}
|
||||
<div class="alert-buttons u-flex">
|
||||
<Button text href={$upgradeURL}>Upgrade plan</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Alert>
|
||||
{/if}
|
||||
|
||||
@@ -47,6 +41,7 @@
|
||||
required
|
||||
bind:files={$createFile.files}
|
||||
allowedFileExtensions={$bucket.allowedFileExtensions}
|
||||
bind:error={fileError}
|
||||
maxSize={isCloud
|
||||
? $bucket.maximumFileSize
|
||||
: ($bucket.maximumFileSize ?? sizeToBytes(service, 'MB', 1000))} />
|
||||
|
||||
Reference in New Issue
Block a user