Finish deployments storage UI

This commit is contained in:
Bradley Schofield
2024-07-23 13:12:48 +09:00
parent ebcf1e98d6
commit 6b03e32c33
6 changed files with 283 additions and 9 deletions
+236
View File
@@ -0,0 +1,236 @@
import { AppwriteException, FunctionUsageRange, type Client, type Payload, type ProjectUsageRange } from '@appwrite.io/console';
/**
* Metric
*/
type Metric = {
/**
* The value of this metric at the timestamp.
*/
value: number;
/**
* The date at which this metric was aggregated in ISO 8601 format.
*/
date: string;
};
/**
* Metric Breakdown
*/
type MetricBreakdown = {
/**
* Resource ID.
*/
resourceId: string;
/**
* Resource name.
*/
name: string;
/**
* The value of this metric at the timestamp.
*/
value: number;
};
/**
* UsageProject
*/
type UsageProject = {
/**
* Total aggregated number of function executions.
*/
executionsTotal: number;
/**
* Total aggregated number of documents.
*/
documentsTotal: number;
/**
* Total aggregated number of databases.
*/
databasesTotal: number;
/**
* Total aggregated number of users.
*/
usersTotal: number;
/**
* Total aggregated sum of files storage size (in bytes).
*/
filesStorageTotal: number;
/**
* Total aggregated sum of deployments storage size (in bytes).
*/
deploymentsStorageTotal: number;
/**
* Total aggregated number of buckets.
*/
bucketsTotal: number;
/**
* Aggregated number of requests per period.
*/
requests: Metric[];
/**
* Aggregated number of consumed bandwidth per period.
*/
network: Metric[];
/**
* Aggregated number of users per period.
*/
users: Metric[];
/**
* Aggregated number of executions per period.
*/
executions: Metric[];
/**
* Aggregated breakdown in totals of executions by functions.
*/
executionsBreakdown: MetricBreakdown[];
/**
* Aggregated breakdown in totals of usage by buckets.
*/
bucketsBreakdown: MetricBreakdown[];
/**
* Aggregated breakdown in totals of usage by deployments.
*/
deploymentsStorageBreakdown: MetricBreakdown[];
};
/**
* UsageFunction
*/
export type UsageFunction = {
/**
* The time range of the usage stats.
*/
range: string;
/**
* Total aggregated number of function deployments.
*/
deploymentsTotal: number;
/**
* Total aggregated sum of function deployments storage.
*/
deploymentsStorageTotal: number;
/**
* Total aggregated number of function builds.
*/
buildsTotal: number;
/**
* total aggregated sum of function builds storage.
*/
buildsStorageTotal: number;
/**
* Total aggregated sum of function builds compute time.
*/
buildsTimeTotal: number;
/**
* Total aggregated number of function executions.
*/
executionsTotal: number;
/**
* Total aggregated sum of function executions compute time.
*/
executionsTimeTotal: number;
/**
* Aggregated number of function deployments per period.
*/
deployments: Metric[];
/**
* Aggregated number of function deployments storage per period.
*/
deploymentsStorage: Metric[];
/**
* Aggregated number of function builds per period.
*/
builds: Metric[];
/**
* Aggregated sum of function builds storage per period.
*/
buildsStorage: Metric[];
/**
* Aggregated sum of function builds compute time per period.
*/
buildsTime: Metric[];
/**
* Aggregated number of function executions per period.
*/
executions: Metric[];
/**
* Aggregated number of function executions compute time per period.
*/
executionsTime: Metric[];
};
export class TempFunctions {
client: Client;
constructor(client: Client) {
this.client = client;
}
/**
* Get project usage stats
*
*
* @param {string} startDate
* @param {string} endDate
* @param {ProjectUsageRange} period
* @throws {AppwriteException}
* @returns {Promise}
*/
async getUsage(startDate: string, endDate: string, period?: ProjectUsageRange): Promise<UsageProject> {
if (typeof startDate === 'undefined') {
throw new AppwriteException('Missing required parameter: "startDate"');
}
if (typeof endDate === 'undefined') {
throw new AppwriteException('Missing required parameter: "endDate"');
}
const apiPath = '/project/usage';
const payload: Payload = {};
if (typeof startDate !== 'undefined') {
payload['startDate'] = startDate;
}
if (typeof endDate !== 'undefined') {
payload['endDate'] = endDate;
}
if (typeof period !== 'undefined') {
payload['period'] = period;
}
const uri = new URL(this.client.config.endpoint + apiPath);
return await this.client.call('get', uri, {
'content-type': 'application/json',
}, payload);
}
/**
* Get function usage
*
*
* @param {string} functionId
* @param {FunctionUsageRange} range
* @throws {AppwriteException}
* @returns {Promise}
*/
async getFunctionUsage(functionId: string, range?: FunctionUsageRange): Promise<UsageFunction> {
if (typeof functionId === 'undefined') {
throw new AppwriteException('Missing required parameter: "functionId"');
}
const apiPath = '/functions/{functionId}/usage'.replace('{functionId}', functionId);
const payload: Payload = {};
if (typeof range !== 'undefined') {
payload['range'] = range;
}
const uri = new URL(this.client.config.endpoint + apiPath);
return await this.client.call('get', uri, {
'content-type': 'application/json',
}, payload);
}
}
+5 -2
View File
@@ -23,6 +23,7 @@ import {
} from '@appwrite.io/console';
import { Billing } from '../sdk/billing';
import { Sources } from '$lib/sdk/sources';
import { TempFunctions } from '$lib/sdk/tempFunctions';
const endpoint = VARS.APPWRITE_ENDPOINT ?? `${globalThis?.location?.origin}/v1`;
@@ -48,7 +49,8 @@ const sdkForProject = {
users: new Users(clientProject),
vcs: new Vcs(clientProject),
proxy: new Proxy(clientProject),
migrations: new Migrations(clientProject)
migrations: new Migrations(clientProject),
tempFunctions: new TempFunctions(clientProject)
};
export const getSdkForProject = (projectId: string) => {
@@ -74,7 +76,8 @@ export const sdk = {
console: new Console(clientConsole),
assistant: new Assistant(clientConsole),
billing: new Billing(clientConsole),
sources: new Sources(clientConsole)
sources: new Sources(clientConsole),
tempFunctions: new TempFunctions(clientConsole)
},
get forProject() {
const projectId = getProjectId();
@@ -5,10 +5,13 @@
import { page } from '$app/stores';
import type { PageData } from './$types';
import { formatNumberWithCommas } from '$lib/helpers/numbers';
import { humanFileSize } from '$lib/helpers/sizeConvertion';
export let data: PageData;
$: total = data.executionsTotal;
$: count = data.executions;
$: deploymentsStorageTotal = data.deploymentsStorageTotal;
$: deploymentsStorage = data.deploymentsStorage;
</script>
<Container>
@@ -46,4 +49,36 @@
]} />
</Card>
{/if}
</Container>
{#if deploymentsStorage}
<Card>
<Heading tag="h6" size="6">{humanFileSize(deploymentsStorageTotal).value}{humanFileSize(deploymentsStorageTotal).unit}</Heading>
<p>Deployments Storage</p>
<div class="u-margin-block-start-16" />
<BarChart
options={{
yAxis: {
axisLabel: {
formatter: (value) =>
value
? `${humanFileSize(+value).value} ${
humanFileSize(+value).unit
}`
: '0'
}
}
}}
series={[
{
name: 'Bandwidth',
data: [
...deploymentsStorage.map((e) => [e.date, e.value])
],
tooltip: {
valueFormatter: (value) =>
`${humanFileSize(+value).value} ${humanFileSize(+value).unit}`
}
}
]} />
</Card>
{/if}
</Container>
@@ -9,7 +9,7 @@ export const load: PageLoad = async ({ params }) => {
const period = isValueOfStringEnum(FunctionUsageRange, params.period)
? params.period
: FunctionUsageRange.ThirtyDays;
return sdk.forProject.functions.getFunctionUsage(params.function, period);
return sdk.forProject.tempFunctions.getFunctionUsage(params.function, period);
} catch (e) {
error(e.code, e.message);
}
@@ -28,7 +28,7 @@
$: executions = data.usage.executions;
$: executionsTotal = data.usage.executionsTotal;
$: storage = data.usage.filesStorageTotal;
$: deployments = data.usage.deploymentsStorageTotal;
$: deploymentsTotal = data.usage.deploymentsStorageTotal;
const tier = data?.currentInvoice?.tier ?? $organization?.billingPlan;
const plan = tierToPlan(tier).name;
@@ -317,8 +317,8 @@
</div>
</Card>
{/if}
{#if deployments}
{@const humanized = humanFileSize(deployments)}
{#if deploymentsTotal}
{@const humanized = humanFileSize(deploymentsTotal)}
<div class="u-flex u-flex-vertical">
<div class="u-flex u-main-space-between">
<p>
@@ -327,7 +327,7 @@
</p>
</div>
</div>
{#if data.usage.bucketsBreakdown.length > 0}
{#if data.usage.deploymentsStorageBreakdown.length > 0}
<Table noMargin noStyles>
<TableHeader>
<TableCellHead width={285}>Function</TableCellHead>
@@ -29,7 +29,7 @@ export const load: PageLoad = async ({ params, parent }) => {
/**
* Workaround because project id might not be populated yet.
*/
getSdkForProject(project).project.getUsage(startDate, endDate)
getSdkForProject(project).tempFunctions.getUsage(startDate, endDate)
]);
if (invoice) {