mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
fix: usage page WIP
This commit is contained in:
@@ -27,3 +27,4 @@ export { default as InputSecret } from './inputSecret.svelte';
|
||||
export { default as Helper } from './helper.svelte';
|
||||
export { default as Label } from './label.svelte';
|
||||
export { default as InputProjectId } from './inputProjectId.svelte';
|
||||
export { default as InputDate } from './inputDate.svelte';
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { FormItem, Helper, Label } from '.';
|
||||
import NullCheckbox from './nullCheckbox.svelte';
|
||||
|
||||
export let label: string;
|
||||
export let showLabel = true;
|
||||
export let optionalText: string | undefined = undefined;
|
||||
export let id: string;
|
||||
export let value = '';
|
||||
export let required = false;
|
||||
export let nullable = false;
|
||||
export let disabled = false;
|
||||
export let readonly = false;
|
||||
export let autofocus = false;
|
||||
export let autocomplete = false;
|
||||
|
||||
let element: HTMLInputElement;
|
||||
let error: string;
|
||||
|
||||
onMount(() => {
|
||||
if (element && autofocus) {
|
||||
element.focus();
|
||||
}
|
||||
});
|
||||
|
||||
function handleInvalid(event: Event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (element.validity.valueMissing) {
|
||||
error = 'This field is required';
|
||||
return;
|
||||
}
|
||||
|
||||
error = element.validationMessage;
|
||||
}
|
||||
|
||||
let prevValue = '';
|
||||
function handleNullChange(e: CustomEvent<boolean>) {
|
||||
const isNull = e.detail;
|
||||
if (isNull) {
|
||||
prevValue = value;
|
||||
value = null;
|
||||
} else {
|
||||
value = prevValue;
|
||||
}
|
||||
}
|
||||
|
||||
$: if (value) {
|
||||
error = null;
|
||||
}
|
||||
|
||||
$: isNullable = nullable && !required;
|
||||
</script>
|
||||
|
||||
<FormItem>
|
||||
<Label {required} {optionalText} hide={!showLabel} for={id}>
|
||||
{label}
|
||||
</Label>
|
||||
|
||||
<div class="input-text-wrapper">
|
||||
<input
|
||||
{id}
|
||||
{disabled}
|
||||
{readonly}
|
||||
{required}
|
||||
step=".001"
|
||||
autocomplete={autocomplete ? 'on' : 'off'}
|
||||
type="date"
|
||||
class="input-text"
|
||||
bind:value
|
||||
bind:this={element}
|
||||
on:invalid={handleInvalid}
|
||||
style:--amount-of-buttons={isNullable ? 2.75 : 1}
|
||||
style:--button-size={isNullable ? '2rem' : '1rem'} />
|
||||
{#if isNullable}
|
||||
<ul
|
||||
class="buttons-list u-cross-center u-gap-8 u-position-absolute u-inset-block-start-8 u-inset-block-end-8 u-inset-inline-end-12">
|
||||
<li class="buttons-list-item">
|
||||
<NullCheckbox checked={value === null} on:change={handleNullChange} />
|
||||
</li>
|
||||
</ul>
|
||||
{/if}
|
||||
</div>
|
||||
{#if error}
|
||||
<Helper type="warning">{error}</Helper>
|
||||
{/if}
|
||||
</FormItem>
|
||||
@@ -25,7 +25,6 @@
|
||||
import { Feedback } from '$lib/components/feedback';
|
||||
import ChangeOrganizationTierCloud from '$routes/console/changeOrganizationTierCloud.svelte';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { readOnly } from '$lib/stores/billing';
|
||||
import { showExcess } from '$routes/console/organization-[organization]/store';
|
||||
|
||||
let showDropdown = false;
|
||||
|
||||
@@ -449,10 +449,16 @@ export class Billing {
|
||||
}
|
||||
|
||||
// TODO: add date range
|
||||
async listUsage(organizationId: string): Promise<OrganizationUsage> {
|
||||
async listUsage(
|
||||
organizationId: string,
|
||||
startDate: string = '',
|
||||
endDate: string = ''
|
||||
): Promise<OrganizationUsage> {
|
||||
const path = `/organizations/${organizationId}/usage`;
|
||||
const params = {
|
||||
organizationId
|
||||
organizationId,
|
||||
startDate,
|
||||
endDate
|
||||
};
|
||||
const uri = new URL(this.client.config.endpoint + path);
|
||||
return await this.client.call(
|
||||
|
||||
@@ -68,7 +68,6 @@ export function getServiceLimit(serviceId: PlanServices): number {
|
||||
if (!isCloud) return 0;
|
||||
if (!serviceId) return 0;
|
||||
const plan = get(plansInfo).plans.find((p) => p.$id === get(organization)?.billingPlan);
|
||||
console.log(plan);
|
||||
return plan[serviceId];
|
||||
}
|
||||
|
||||
|
||||
@@ -6,18 +6,37 @@
|
||||
import { wizard } from '$lib/stores/wizard.js';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import UsageRates from '$routes/console/wizard/cloudOrganization/usageRates.svelte';
|
||||
import { InputDate, InputSelect } from '$lib/elements/forms';
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
const tier = tierToPlan($organization?.billingPlan)?.name;
|
||||
|
||||
export let data;
|
||||
let showRates = false;
|
||||
let period = 'current';
|
||||
|
||||
$: console.log(data.organizationUsage.users);
|
||||
async function handlePeriodChange() {
|
||||
if (
|
||||
period === 'current' &&
|
||||
!$page.url.pathname.includes('usage/current') &&
|
||||
$page.url.pathname !== `/console/organization-${$organization.$id}/usage`
|
||||
) {
|
||||
await goto(`/console/organization-${$organization.$id}/usage/current`);
|
||||
}
|
||||
if (period === 'previous' && !$page.url.pathname.includes('usage/previous')) {
|
||||
await goto(`/console/organization-${$organization.$id}/usage/previous`);
|
||||
}
|
||||
if (period === 'custom' && !$page.url.pathname.includes('usage/custom')) {
|
||||
console.log('test');
|
||||
// await goto(`/console/organization-${$organization.$id}/usage/custom`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<Heading tag="h2" size="5">Usage</Heading>
|
||||
<div class="u-flex u-main-space-between common-section">
|
||||
<div class="u-flex u-main-space-between common-section u-cross-center">
|
||||
{#if $organization.billingPlan === 'tier-2'}
|
||||
<p class="text">
|
||||
On the Scale plan, you'll be charged only for any usage that exceeds the thresholds
|
||||
@@ -36,10 +55,32 @@
|
||||
>.
|
||||
</p>
|
||||
{/if}
|
||||
<div class="u-flex u-gap-8">
|
||||
|
||||
<InputDate id="date" label="test" showLabel={false}></InputDate>
|
||||
|
||||
<div class="u-flex u-gap-8 u-cross-center">
|
||||
<p class="text">Usage period:</p>
|
||||
|
||||
JANUARY 2021
|
||||
<InputSelect
|
||||
id="period"
|
||||
label="Usage period"
|
||||
showLabel={false}
|
||||
bind:value={period}
|
||||
on:change={handlePeriodChange}
|
||||
options={[
|
||||
{
|
||||
label: 'Current billing cycle',
|
||||
value: 'current'
|
||||
},
|
||||
{
|
||||
label: 'Previous billing cycle',
|
||||
value: 'previous'
|
||||
},
|
||||
{
|
||||
label: 'Choose dates',
|
||||
value: 'custom'
|
||||
}
|
||||
]}></InputSelect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
import type { Organization } from '$lib/stores/organization';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ params }) => {
|
||||
const usage = await sdk.forConsole.billing.listUsage(params.organization);
|
||||
export const load: PageLoad = async ({ params, parent, url }) => {
|
||||
const { period } = params;
|
||||
const parentData = await parent();
|
||||
const org = parentData.organization as Organization;
|
||||
const today = new Date().toISOString();
|
||||
let startDate: string;
|
||||
let endDate: string;
|
||||
|
||||
if (period === 'current') {
|
||||
startDate = org.billingCurrentInvoiceDate;
|
||||
endDate = today;
|
||||
} else if (period === 'previous') {
|
||||
const prevDate = new Date(org.billingCurrentInvoiceDate);
|
||||
prevDate.setDate(prevDate.getDate() - 30);
|
||||
startDate = prevDate.toISOString();
|
||||
endDate = org.billingCurrentInvoiceDate;
|
||||
} else if (period === 'custom') {
|
||||
startDate = url.searchParams.get('start') ?? org.billingCurrentInvoiceDate;
|
||||
endDate = url.searchParams.get('end') ?? today;
|
||||
}
|
||||
const usage = await sdk.forConsole.billing.listUsage(
|
||||
params.organization,
|
||||
startDate ?? org.billingCurrentInvoiceDate,
|
||||
endDate ?? today
|
||||
);
|
||||
console.log(usage);
|
||||
return {
|
||||
organizationUsage: usage
|
||||
|
||||
Reference in New Issue
Block a user