mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: butget alerts and invoices
This commit is contained in:
@@ -4,10 +4,16 @@
|
||||
export let href: string;
|
||||
export let icon: string = null;
|
||||
export let disabled = false;
|
||||
export let external = false;
|
||||
</script>
|
||||
|
||||
<li class="drop-list-item" on:click on:keyup={clickOnEnter}>
|
||||
<a {href} class="drop-button" class:is-disabled={disabled}>
|
||||
<a
|
||||
{href}
|
||||
class="drop-button"
|
||||
class:is-disabled={disabled}
|
||||
target={external ? '_blank' : ''}
|
||||
rel={external ? 'noopener noreferrer' : ''}>
|
||||
<span class="text"><slot /></span>
|
||||
{#if icon}
|
||||
<span class={`icon-${icon}`} aria-hidden="true" />
|
||||
|
||||
@@ -214,7 +214,11 @@ export class Billing {
|
||||
);
|
||||
}
|
||||
|
||||
async updateBudget(organizationId: string, budget: number, alert: number[]): Promise<string> {
|
||||
async updateBudget(
|
||||
organizationId: string,
|
||||
budget: number,
|
||||
alert: number[]
|
||||
): Promise<Organization> {
|
||||
const path = `/organizations/${organizationId}/budget`;
|
||||
const params = {
|
||||
organizationId,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { CardGrid, Heading } from '$lib/components';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import { Button, Form, FormList, InputSelectSearch } from '$lib/elements/forms';
|
||||
import {
|
||||
Table,
|
||||
@@ -11,12 +13,13 @@
|
||||
TableHeader,
|
||||
TableRow
|
||||
} from '$lib/elements/table';
|
||||
import { symmetricDifference } from '$lib/helpers/array';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import UsageRates from '$routes/console/wizard/cloudOrganization/usageRates.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let budget: number;
|
||||
let showRates = false;
|
||||
let search: string;
|
||||
let selectedAlert: number;
|
||||
@@ -29,6 +32,10 @@
|
||||
{ value: 100, label: '100%' }
|
||||
];
|
||||
|
||||
onMount(() => {
|
||||
alerts = $organization?.budgetAlert ?? [];
|
||||
});
|
||||
|
||||
function addAlert() {
|
||||
if (alerts.some((alert) => alert === selectedAlert)) {
|
||||
return;
|
||||
@@ -40,17 +47,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: add budget value that has been fetched
|
||||
async function updateBudget() {
|
||||
try {
|
||||
await sdk.forConsole.billing.updateBudget($organization.$id, budget, alerts);
|
||||
trackEvent(Submit.BudgetCapUpdate, {
|
||||
await sdk.forConsole.billing.updateBudget(
|
||||
$organization.$id,
|
||||
$organization.billingBudget,
|
||||
alerts
|
||||
});
|
||||
);
|
||||
invalidate(Dependencies.ORGANIZATION);
|
||||
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `Budget cap enabled for ${$organization.name}`
|
||||
});
|
||||
trackEvent(Submit.BudgetCapUpdate, {
|
||||
alerts
|
||||
});
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
@@ -59,11 +71,15 @@
|
||||
trackError(error, Submit.BudgetCapUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
$: isButtonDisabled = symmetricDifference(alerts, $organization.budgetAlert).length === 0;
|
||||
|
||||
$: console.log($organization.budgetAlert, alerts);
|
||||
</script>
|
||||
|
||||
<Form onSubmit={updateBudget}>
|
||||
<CardGrid>
|
||||
<Heading tag="h2" size="6">Budget alert aondition</Heading>
|
||||
<Heading tag="h2" size="6">Budget alert condition</Heading>
|
||||
|
||||
<p class="text">
|
||||
Get notified by email when your organization meets or exceeds a percent of your
|
||||
@@ -71,16 +87,21 @@
|
||||
</p>
|
||||
<svelte:fragment slot="aside">
|
||||
<FormList>
|
||||
<InputSelectSearch
|
||||
label="Percentage (%) of budget cap"
|
||||
placeholder="Select a percentage"
|
||||
id="alerts"
|
||||
{options}
|
||||
bind:search
|
||||
bind:value={selectedAlert}
|
||||
on:select={() => (search = selectedAlert.toString())} />
|
||||
<Button secondary disabled={alerts.length > 2} on:click={addAlert}
|
||||
>Add alert</Button>
|
||||
<div class="u-flex u-gap-16">
|
||||
<InputSelectSearch
|
||||
label="Percentage (%) of budget cap"
|
||||
placeholder="Select a percentage"
|
||||
id="alerts"
|
||||
{options}
|
||||
bind:search
|
||||
bind:value={selectedAlert}
|
||||
on:select={() => (search = selectedAlert.toString())} />
|
||||
<div style="align-self: flex-end">
|
||||
<Button secondary disabled={alerts.length > 2} on:click={addAlert}>
|
||||
Add alert
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</FormList>
|
||||
|
||||
{#if alerts.length}
|
||||
@@ -93,7 +114,7 @@
|
||||
{#each alerts as alert}
|
||||
<TableRow>
|
||||
<TableCellText title="Percentage">
|
||||
{alert}
|
||||
{alert}%
|
||||
</TableCellText>
|
||||
<TableCell>
|
||||
<Button
|
||||
@@ -113,7 +134,7 @@
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="actions">
|
||||
<Button submit>Update</Button>
|
||||
<Button disabled={isButtonDisabled} submit>Update</Button>
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
</Form>
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { CardGrid, DropList, EmptySearch, Heading, PaginationInline } from '$lib/components';
|
||||
import DropListItem from '$lib/components/dropListItem.svelte';
|
||||
import {
|
||||
CardGrid,
|
||||
DropList,
|
||||
DropListLink,
|
||||
EmptySearch,
|
||||
Heading,
|
||||
PaginationInline
|
||||
} from '$lib/components';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import {
|
||||
@@ -22,12 +28,21 @@
|
||||
let selectedInvoice: string;
|
||||
let offset = 0;
|
||||
|
||||
let downloadLink: string;
|
||||
let viewLink: string;
|
||||
|
||||
async function download() {
|
||||
sdk.forConsole.billing.downloadInvoice($page.params.organization, selectedInvoice);
|
||||
return await sdk.forConsole.billing.downloadInvoice(
|
||||
$page.params.organization,
|
||||
selectedInvoice
|
||||
);
|
||||
}
|
||||
|
||||
async function view() {
|
||||
sdk.forConsole.billing.getInvoiceView($page.params.organization, selectedInvoice);
|
||||
return await sdk.forConsole.billing.getInvoiceView(
|
||||
$page.params.organization,
|
||||
selectedInvoice
|
||||
);
|
||||
}
|
||||
|
||||
async function request() {
|
||||
@@ -37,6 +52,15 @@
|
||||
]);
|
||||
}
|
||||
|
||||
$: if (selectedInvoice) {
|
||||
download().then((res) => {
|
||||
downloadLink = res.toString();
|
||||
});
|
||||
view().then((res) => {
|
||||
viewLink = res.toString();
|
||||
});
|
||||
}
|
||||
|
||||
$: if (offset !== null) {
|
||||
request();
|
||||
}
|
||||
@@ -82,25 +106,18 @@
|
||||
noMargin
|
||||
ariaLabel="More options"
|
||||
on:click={() => {
|
||||
selectedInvoice = invoice.$id;
|
||||
showDropdown[i] = !showDropdown[i];
|
||||
}}>
|
||||
<span class="icon-dots-horizontal" aria-hidden="true" />
|
||||
</Button>
|
||||
<svelte:fragment slot="list">
|
||||
<DropListItem
|
||||
icon="external-link"
|
||||
on:click={() => {
|
||||
selectedInvoice = invoice.$id;
|
||||
view();
|
||||
}}>
|
||||
<DropListLink icon="external-link" external href={viewLink}>
|
||||
View invoice
|
||||
</DropListItem>
|
||||
<DropListItem
|
||||
icon="download"
|
||||
on:click={() => {
|
||||
selectedInvoice = invoice.$id;
|
||||
download();
|
||||
}}>Download PDF</DropListItem>
|
||||
</DropListLink>
|
||||
<DropListLink icon="download" external href={downloadLink}>
|
||||
Download PDF
|
||||
</DropListLink>
|
||||
</svelte:fragment>
|
||||
</DropList>
|
||||
</TableCell>
|
||||
|
||||
Reference in New Issue
Block a user