mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge pull request #1693 from appwrite/add-image-transformation-stats
feat: added image transformation usage to org & buckets
This commit is contained in:
+1
-1
@@ -19,7 +19,7 @@
|
||||
"e2e:ui": "playwright test tests/e2e --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "1.5.1",
|
||||
"@appwrite.io/console": "1.5.2",
|
||||
"@appwrite.io/pink": "0.25.0",
|
||||
"@appwrite.io/pink-icons": "0.25.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
|
||||
Generated
+5
-5
@@ -9,8 +9,8 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@appwrite.io/console':
|
||||
specifier: 1.5.1
|
||||
version: 1.5.1
|
||||
specifier: 1.5.2
|
||||
version: 1.5.2
|
||||
'@appwrite.io/pink':
|
||||
specifier: 0.25.0
|
||||
version: 0.25.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.5.1':
|
||||
resolution: {integrity: sha512-H0fkBprsxXjOhbrE+MqXt1e4Gx4QeRdHuvMs7UxqGr2fAVEqh4ez2yk40A0ZSQvvN+rqLduoItMHQFl+sCPbtQ==}
|
||||
'@appwrite.io/console@1.5.2':
|
||||
resolution: {integrity: sha512-9nNZzxoQcpm5C5pKlGJLWxsEJ4sr5mdt01Hg6M8QpfMtsRe0gjaPa7WGrGBepRnZVKPDNpozh3Hua7nqgx4aEA==}
|
||||
|
||||
'@appwrite.io/pink-icons@0.25.0':
|
||||
resolution: {integrity: sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q==}
|
||||
@@ -3837,7 +3837,7 @@ snapshots:
|
||||
|
||||
'@analytics/type-utils@0.6.2': {}
|
||||
|
||||
'@appwrite.io/console@1.5.1': {}
|
||||
'@appwrite.io/console@1.5.2': {}
|
||||
|
||||
'@appwrite.io/pink-icons@0.25.0': {}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
export let maxValue: string | undefined = undefined;
|
||||
export let maxUnit: string | undefined = undefined;
|
||||
export let progressValue: number;
|
||||
export let progressMax: number;
|
||||
export let progressMax: number | undefined = undefined;
|
||||
export let showBar = true;
|
||||
export let progressBarData: Array<ProgressbarData> = [];
|
||||
|
||||
@@ -14,20 +14,24 @@
|
||||
</script>
|
||||
|
||||
<section class="progress-bar">
|
||||
{#if currentValue !== undefined && currentUnit !== undefined && progress !== undefined && maxValue !== undefined}
|
||||
{#if currentValue !== undefined && currentUnit !== undefined && progress !== undefined}
|
||||
<div class="u-flex u-flex-vertical">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<p>
|
||||
<span class="heading-level-4">{currentValue}</span>
|
||||
<span class="body-text-1 u-bold">{currentUnit}</span>
|
||||
</p>
|
||||
<p class="heading-level-4">{progress}%</p>
|
||||
{#if progressMax !== undefined}
|
||||
<p class="heading-level-4">{progress}%</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<p class="body-text-2">
|
||||
{maxValue}
|
||||
{maxUnit ? maxUnit : ''}
|
||||
</p>
|
||||
{#if maxValue !== undefined}
|
||||
<p class="body-text-2">
|
||||
{maxValue}
|
||||
{maxUnit ? maxUnit : ''}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if showBar && progressBarData.length > 0}
|
||||
|
||||
+21
-18
@@ -68,12 +68,12 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { BarChart } from '$lib/charts';
|
||||
import { formatNumberWithCommas } from '$lib/helpers/numbers';
|
||||
import { Card, SecondaryTabs, SecondaryTabsItem, Heading } from '$lib/components';
|
||||
import { ProjectUsageRange, type Models } from '@appwrite.io/console';
|
||||
import { page } from '$app/stores';
|
||||
import { BarChart } from '$lib/charts';
|
||||
import { Card, Heading, SecondaryTabs, SecondaryTabsItem } from '$lib/components';
|
||||
import { formatNumberWithCommas } from '$lib/helpers/numbers';
|
||||
import { Container } from '$lib/layout';
|
||||
import { ProjectUsageRange, type Models } from '@appwrite.io/console';
|
||||
|
||||
type MetricMetadata = {
|
||||
title: string;
|
||||
@@ -85,24 +85,27 @@
|
||||
export let count: Models.Metric[];
|
||||
export let countMetadata: MetricMetadata;
|
||||
export let path: string = null;
|
||||
export let hideSelectPeriod: boolean = false;
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<div class="u-flex u-main-space-between common-section">
|
||||
<Heading tag="h2" size="5">{title}</Heading>
|
||||
<SecondaryTabs>
|
||||
<SecondaryTabsItem href={`${path}/24h`} disabled={$page.params.period === '24h'}>
|
||||
24h
|
||||
</SecondaryTabsItem>
|
||||
<SecondaryTabsItem
|
||||
href={`${path}/30d`}
|
||||
disabled={!$page.params.period || $page.params.period === '30d'}>
|
||||
30d
|
||||
</SecondaryTabsItem>
|
||||
<SecondaryTabsItem href={`${path}/90d`} disabled={$page.params.period === '90d'}>
|
||||
90d
|
||||
</SecondaryTabsItem>
|
||||
</SecondaryTabs>
|
||||
{#if !hideSelectPeriod}
|
||||
<SecondaryTabs>
|
||||
<SecondaryTabsItem href={`${path}/24h`} disabled={$page.params.period === '24h'}>
|
||||
24h
|
||||
</SecondaryTabsItem>
|
||||
<SecondaryTabsItem
|
||||
href={`${path}/30d`}
|
||||
disabled={!$page.params.period || $page.params.period === '30d'}>
|
||||
30d
|
||||
</SecondaryTabsItem>
|
||||
<SecondaryTabsItem href={`${path}/90d`} disabled={$page.params.period === '90d'}>
|
||||
90d
|
||||
</SecondaryTabsItem>
|
||||
</SecondaryTabs>
|
||||
{/if}
|
||||
</div>
|
||||
<Card>
|
||||
{#if count}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { Client, Models } from '@appwrite.io/console';
|
||||
import type { OrganizationError, Organization, OrganizationList } from '../stores/organization';
|
||||
import type { PaymentMethod } from '@stripe/stripe-js';
|
||||
import type { Tier } from '$lib/stores/billing';
|
||||
import type { Campaign } from '$lib/stores/campaigns';
|
||||
import type { Client, Models } from '@appwrite.io/console';
|
||||
import type { PaymentMethod } from '@stripe/stripe-js';
|
||||
import type { Organization, OrganizationError, OrganizationList } from '../stores/organization';
|
||||
|
||||
export type PaymentMethodData = {
|
||||
$id: string;
|
||||
@@ -213,11 +213,13 @@ export type OrganizationUsage = {
|
||||
executions: Array<Models.Metric>;
|
||||
databasesReads: Array<Models.Metric>;
|
||||
databasesWrites: Array<Models.Metric>;
|
||||
imageTransformations: Array<Models.Metric>;
|
||||
executionsTotal: number;
|
||||
filesStorageTotal: number;
|
||||
buildsStorageTotal: number;
|
||||
databasesReadsTotal: number;
|
||||
databasesWritesTotal: number;
|
||||
imageTransformationsTotal: number;
|
||||
deploymentsStorageTotal: number;
|
||||
executionsMBSecondsTotal: number;
|
||||
buildsMBSecondsTotal: number;
|
||||
@@ -235,6 +237,7 @@ export type OrganizationUsage = {
|
||||
users: number;
|
||||
authPhoneTotal: number;
|
||||
authPhoneEstimate: number;
|
||||
imageTransformations: number;
|
||||
}>;
|
||||
authPhoneTotal: number;
|
||||
authPhoneEstimate: number;
|
||||
@@ -313,6 +316,7 @@ export type Plan = {
|
||||
order: number;
|
||||
bandwidth: number;
|
||||
storage: number;
|
||||
imageTransformations: number;
|
||||
webhooks: number;
|
||||
users: number;
|
||||
teams: number;
|
||||
|
||||
+19
-1
@@ -185,6 +185,14 @@ export type UsageBuckets = {
|
||||
* Aggregated statistics of bucket storage files per period.
|
||||
*/
|
||||
storage: Metric[];
|
||||
/**
|
||||
* Aggregated statistics of bucket image transformations per period.
|
||||
*/
|
||||
imageTransformations: Metric[];
|
||||
/**
|
||||
* Total aggregated number of bucket image transformations.
|
||||
*/
|
||||
imageTransformationsTotal: number;
|
||||
};
|
||||
/**
|
||||
* UsageFunctions
|
||||
@@ -311,7 +319,17 @@ export type UsageProject = {
|
||||
authPhoneEstimate: number;
|
||||
|
||||
/**
|
||||
* Aggregated statistics of total number SMS by country
|
||||
* Aggregated statistics of total number SMS by country.
|
||||
*/
|
||||
authPhoneCountriesBreakdown: Models.MetricBreakdown[];
|
||||
|
||||
/**
|
||||
* Array of image transformations per period.
|
||||
*/
|
||||
imageTransformations: Metric[];
|
||||
|
||||
/**
|
||||
* Aggregated statistics of total number of image transformations.
|
||||
*/
|
||||
imageTransformationsTotal: number;
|
||||
};
|
||||
|
||||
+30
-29
@@ -1,37 +1,37 @@
|
||||
import { page } from '$app/stores';
|
||||
import { derived, get, writable } from 'svelte/store';
|
||||
import { sdk } from './sdk';
|
||||
import { organization, type Organization, type OrganizationError } from './organization';
|
||||
import type {
|
||||
InvoiceList,
|
||||
AddressesList,
|
||||
Invoice,
|
||||
PaymentList,
|
||||
PlansMap,
|
||||
PaymentMethodData,
|
||||
Plan,
|
||||
Aggregation
|
||||
} from '$lib/sdk/billing';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { cachedStore } from '$lib/helpers/cache';
|
||||
import { Query } from '@appwrite.io/console';
|
||||
import { headerAlert } from './headerAlert';
|
||||
import PaymentAuthRequired from '$lib/components/billing/alerts/paymentAuthRequired.svelte';
|
||||
import { addNotification, notifications } from './notifications';
|
||||
import { browser } from '$app/environment';
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { activeHeaderAlert, orgMissingPaymentMethod } from '$routes/(console)/store';
|
||||
import MarkedForDeletion from '$lib/components/billing/alerts/markedForDeletion.svelte';
|
||||
import { BillingPlan, NEW_DEV_PRO_UPGRADE_COUPON } from '$lib/constants';
|
||||
import PaymentMandate from '$lib/components/billing/alerts/paymentMandate.svelte';
|
||||
import MissingPaymentMethod from '$lib/components/billing/alerts/missingPaymentMethod.svelte';
|
||||
import LimitReached from '$lib/components/billing/alerts/limitReached.svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import LimitReached from '$lib/components/billing/alerts/limitReached.svelte';
|
||||
import MarkedForDeletion from '$lib/components/billing/alerts/markedForDeletion.svelte';
|
||||
import MissingPaymentMethod from '$lib/components/billing/alerts/missingPaymentMethod.svelte';
|
||||
import newDevUpgradePro from '$lib/components/billing/alerts/newDevUpgradePro.svelte';
|
||||
import PaymentAuthRequired from '$lib/components/billing/alerts/paymentAuthRequired.svelte';
|
||||
import PaymentMandate from '$lib/components/billing/alerts/paymentMandate.svelte';
|
||||
import { BillingPlan, NEW_DEV_PRO_UPGRADE_COUPON } from '$lib/constants';
|
||||
import { cachedStore } from '$lib/helpers/cache';
|
||||
import { sizeToBytes, type Size } from '$lib/helpers/sizeConvertion';
|
||||
import { user } from './user';
|
||||
import { browser } from '$app/environment';
|
||||
import type {
|
||||
AddressesList,
|
||||
Aggregation,
|
||||
Invoice,
|
||||
InvoiceList,
|
||||
PaymentList,
|
||||
PaymentMethodData,
|
||||
Plan,
|
||||
PlansMap
|
||||
} from '$lib/sdk/billing';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { activeHeaderAlert, orgMissingPaymentMethod } from '$routes/(console)/store';
|
||||
import { Query } from '@appwrite.io/console';
|
||||
import { derived, get, writable } from 'svelte/store';
|
||||
import { headerAlert } from './headerAlert';
|
||||
import { addNotification, notifications } from './notifications';
|
||||
import { organization, type Organization, type OrganizationError } from './organization';
|
||||
import { canSeeBilling } from './roles';
|
||||
import { sdk } from './sdk';
|
||||
import { user } from './user';
|
||||
|
||||
export type Tier = 'tier-0' | 'tier-1' | 'tier-2' | 'auto-1' | 'cont-1' | 'ent-1';
|
||||
|
||||
@@ -130,7 +130,8 @@ export type PlanServices =
|
||||
| 'users'
|
||||
| 'usersAddon'
|
||||
| 'webhooks'
|
||||
| 'authPhone';
|
||||
| 'authPhone'
|
||||
| 'imageTransformations';
|
||||
|
||||
export function getServiceLimit(serviceId: PlanServices, tier: Tier = null, plan?: Plan): number {
|
||||
if (!isCloud) return 0;
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { tooltip } from '$lib/actions/tooltip';
|
||||
import { BarChart, Legend } from '$lib/charts';
|
||||
import { Card, CardGrid, Heading, ProgressBarBig } from '$lib/components';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { formatCurrency, formatNumberWithCommas } from '$lib/helpers/numbers';
|
||||
import { bytesToSize, humanFileSize, mbSecondsToGBHours } from '$lib/helpers/sizeConvertion';
|
||||
import { formatNum } from '$lib/helpers/string';
|
||||
import { Container } from '$lib/layout';
|
||||
import { accumulateFromEndingTotal, total } from '$lib/layout/usage.svelte';
|
||||
import type { OrganizationUsage } from '$lib/sdk/billing';
|
||||
import {
|
||||
getServiceLimit,
|
||||
showUsageRatesModal,
|
||||
@@ -8,18 +18,8 @@
|
||||
upgradeURL
|
||||
} from '$lib/stores/billing';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { bytesToSize, humanFileSize, mbSecondsToGBHours } from '$lib/helpers/sizeConvertion';
|
||||
import { BarChart, Legend } from '$lib/charts';
|
||||
import ProjectBreakdown from './ProjectBreakdown.svelte';
|
||||
import { formatNum } from '$lib/helpers/string';
|
||||
import { accumulateFromEndingTotal, total } from '$lib/layout/usage.svelte';
|
||||
import type { OrganizationUsage } from '$lib/sdk/billing';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import TotalMembers from './totalMembers.svelte';
|
||||
import { tooltip } from '$lib/actions/tooltip';
|
||||
import { formatCurrency, formatNumberWithCommas } from '$lib/helpers/numbers';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -260,6 +260,60 @@
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Image transformations</Heading>
|
||||
|
||||
<p class="text">
|
||||
The total number of unique image transformations across all projects in your
|
||||
organization. <a
|
||||
href="https://appwrite.io/docs/advanced/platform/image-transformations"
|
||||
class="link">Learn more</a
|
||||
>.
|
||||
</p>
|
||||
<svelte:fragment slot="aside">
|
||||
{#if data.organizationUsage.imageTransformationsTotal}
|
||||
{@const current = data.organizationUsage.imageTransformationsTotal}
|
||||
<ProgressBarBig
|
||||
currentUnit="Transformations"
|
||||
currentValue={formatNum(current)}
|
||||
progressValue={current}
|
||||
showBar={false} />
|
||||
<BarChart
|
||||
options={{
|
||||
yAxis: {
|
||||
axisLabel: {
|
||||
formatter: formatNum
|
||||
}
|
||||
}
|
||||
}}
|
||||
series={[
|
||||
{
|
||||
name: 'Image transformations',
|
||||
data: [
|
||||
...(data.organizationUsage.imageTransformations ?? []).map((e) => [
|
||||
e.date,
|
||||
e.value
|
||||
])
|
||||
]
|
||||
}
|
||||
]} />
|
||||
{#if projects?.length > 0}
|
||||
<ProjectBreakdown {projects} metric="imageTransformations" {data} />
|
||||
{/if}
|
||||
{:else}
|
||||
<Card isDashed>
|
||||
<div class="u-flex u-cross-center u-flex-vertical u-main-center u-flex">
|
||||
<span
|
||||
class="icon-chart-square-bar text-large"
|
||||
aria-hidden="true"
|
||||
style="font-size: 32px;" />
|
||||
<p class="u-bold">No data to show</p>
|
||||
</div>
|
||||
</Card>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Executions</Heading>
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { Invoice } from '$lib/sdk/billing';
|
||||
import { type Organization } from '$lib/stores/organization';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { Query, type Models } from '@appwrite.io/console';
|
||||
import type { PageLoad } from './$types';
|
||||
import { type Organization } from '$lib/stores/organization';
|
||||
import type { Invoice } from '$lib/sdk/billing';
|
||||
|
||||
export const load: PageLoad = async ({ params, parent }) => {
|
||||
const { invoice } = params;
|
||||
@@ -33,7 +33,9 @@ export const load: PageLoad = async ({ params, parent }) => {
|
||||
databasesReads: null,
|
||||
databasesWrites: null,
|
||||
databasesReadsTotal: null,
|
||||
databasesWritesTotal: null
|
||||
databasesWritesTotal: null,
|
||||
imageTransformations: null,
|
||||
imageTransformationsTotal: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import { base } from '$app/paths';
|
||||
import { Collapsible, CollapsibleItem } from '$lib/components';
|
||||
import {
|
||||
TableBody,
|
||||
@@ -13,9 +13,9 @@
|
||||
import { abbreviateNumber, formatCurrency, formatNumberWithCommas } from '$lib/helpers/numbers';
|
||||
import { humanFileSize } from '$lib/helpers/sizeConvertion';
|
||||
import type { OrganizationUsage } from '$lib/sdk/billing';
|
||||
import { base } from '$app/paths';
|
||||
import { canSeeProjects } from '$lib/stores/roles';
|
||||
import { onMount } from 'svelte';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
type Metric =
|
||||
| 'users'
|
||||
@@ -24,7 +24,8 @@
|
||||
| 'executions'
|
||||
| 'authPhoneTotal'
|
||||
| 'databasesReads'
|
||||
| 'databasesWrites';
|
||||
| 'databasesWrites'
|
||||
| 'imageTransformations';
|
||||
|
||||
type Estimate = 'authPhoneEstimate';
|
||||
|
||||
@@ -93,6 +94,7 @@
|
||||
}
|
||||
|
||||
switch (metric) {
|
||||
case 'imageTransformations':
|
||||
case 'authPhoneTotal':
|
||||
return formatNumberWithCommas(value);
|
||||
case 'executions':
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { CardGrid, Heading, Card, ProgressBarBig } from '$lib/components';
|
||||
import { base } from '$app/paths';
|
||||
import { BarChart, Legend } from '$lib/charts';
|
||||
import { Card, CardGrid, Heading, ProgressBarBig } from '$lib/components';
|
||||
import Collapsible from '$lib/components/collapsible.svelte';
|
||||
import CollapsibleItem from '$lib/components/collapsibleItem.svelte';
|
||||
import { BillingPlan } from '$lib/constants.js';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import {
|
||||
TableRow,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableCellHead,
|
||||
TableHeader,
|
||||
Table,
|
||||
TableRow,
|
||||
TableRowLink
|
||||
} from '$lib/elements/table';
|
||||
import { getCountryName } from '$lib/helpers/diallingCodes.js';
|
||||
import { formatCurrency, formatNumberWithCommas } from '$lib/helpers/numbers';
|
||||
import { bytesToSize, humanFileSize, mbSecondsToGBHours } from '$lib/helpers/sizeConvertion';
|
||||
import { formatNum } from '$lib/helpers/string';
|
||||
import { Container } from '$lib/layout';
|
||||
import { total } from '$lib/layout/usage.svelte';
|
||||
import { showUsageRatesModal, tierToPlan, upgradeURL } from '$lib/stores/billing';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { bytesToSize, humanFileSize, mbSecondsToGBHours } from '$lib/helpers/sizeConvertion';
|
||||
import { BarChart, Legend } from '$lib/charts';
|
||||
import { formatNum } from '$lib/helpers/string';
|
||||
import { total } from '$lib/layout/usage.svelte';
|
||||
import { BillingPlan } from '$lib/constants.js';
|
||||
import { base } from '$app/paths';
|
||||
import { formatCurrency, formatNumberWithCommas } from '$lib/helpers/numbers';
|
||||
import Collapsible from '$lib/components/collapsible.svelte';
|
||||
import CollapsibleItem from '$lib/components/collapsibleItem.svelte';
|
||||
import { getCountryName } from '$lib/helpers/diallingCodes.js';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
data.usage.filesStorageTotal +
|
||||
data.usage.deploymentsStorageTotal +
|
||||
data.usage.buildsStorageTotal;
|
||||
|
||||
$: imageTransformations = data.usage.imageTransformations;
|
||||
$: imageTransformationsTotal = data.usage.imageTransformationsTotal;
|
||||
$: dbReads = data.usage.databasesReads;
|
||||
$: dbWrites = data.usage.databasesWrites;
|
||||
|
||||
@@ -246,6 +247,49 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Image transformations</Heading>
|
||||
|
||||
<p class="text">Total unique image transformations in your project.</p>
|
||||
|
||||
<svelte:fragment slot="aside">
|
||||
{#if imageTransformations}
|
||||
{@const current = formatNum(imageTransformationsTotal)}
|
||||
<div class="u-flex u-flex-vertical">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<p>
|
||||
<span class="heading-level-4">{current}</span>
|
||||
<span class="body-text-1 u-bold">Transformations</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<BarChart
|
||||
options={{
|
||||
yAxis: {
|
||||
axisLabel: {
|
||||
formatter: formatNum
|
||||
}
|
||||
}
|
||||
}}
|
||||
series={[
|
||||
{
|
||||
name: 'Image transformations',
|
||||
data: [...imageTransformations.map((e) => [e.date, e.value])]
|
||||
}
|
||||
]} />
|
||||
{:else}
|
||||
<Card isDashed>
|
||||
<div class="u-flex u-cross-center u-flex-vertical u-main-center u-flex">
|
||||
<span
|
||||
class="icon-chart-square-bar text-large"
|
||||
aria-hidden="true"
|
||||
style="font-size: 32px;" />
|
||||
<p class="u-bold">No data to show</p>
|
||||
</div>
|
||||
</Card>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Executions</Heading>
|
||||
|
||||
|
||||
+17
-4
@@ -5,16 +5,29 @@
|
||||
import type { PageData } from './$types';
|
||||
|
||||
export let data: PageData;
|
||||
$: total = data.filesTotal;
|
||||
$: count = data.files;
|
||||
$: filesTotal = data.filesTotal;
|
||||
$: files = data.files;
|
||||
$: transformationsTotal = data.imageTransformationsTotal;
|
||||
$: transformations = data.imageTransformations;
|
||||
</script>
|
||||
|
||||
<Usage
|
||||
title="Files"
|
||||
path={`${base}/project-${$page.params.project}/storage/bucket-${$page.params.bucket}/usage`}
|
||||
{total}
|
||||
{count}
|
||||
total={filesTotal}
|
||||
count={files}
|
||||
countMetadata={{
|
||||
legend: 'Files',
|
||||
title: 'Total files'
|
||||
}} />
|
||||
|
||||
<Usage
|
||||
title="Image transformations"
|
||||
path={`${base}/project-${$page.params.project}/storage/bucket-${$page.params.bucket}/usage`}
|
||||
total={transformationsTotal}
|
||||
count={transformations}
|
||||
countMetadata={{
|
||||
legend: 'Image transformations',
|
||||
title: 'Total transformations'
|
||||
}}
|
||||
hideSelectPeriod />
|
||||
|
||||
+7
-6
@@ -1,8 +1,7 @@
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import type { Metric, UsageBuckets } from '$lib/sdk/usage';
|
||||
import type { PageLoad } from './$types';
|
||||
import { StorageUsageRange } from '@appwrite.io/console';
|
||||
import { isValueOfStringEnum } from '$lib/helpers/types';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { StorageUsageRange, type Models } from '@appwrite.io/console';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ params }) => {
|
||||
const period = isValueOfStringEnum(StorageUsageRange, params.period)
|
||||
@@ -11,10 +10,12 @@ export const load: PageLoad = async ({ params }) => {
|
||||
const response = (await sdk.forProject.storage.getBucketUsage(
|
||||
params.bucket,
|
||||
period
|
||||
)) as unknown as UsageBuckets;
|
||||
)) as unknown as Models.UsageBuckets;
|
||||
|
||||
return {
|
||||
filesTotal: response.filesTotal,
|
||||
files: response.files as Metric[]
|
||||
files: response.files as Models.Metric[],
|
||||
imageTransformationsTotal: response.imageTransformationsTotal,
|
||||
imageTransformations: response.imageTransformations as Models.Metric[]
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user