mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge pull request #1353 from appwrite/feat-new-multipart-progressbar
Feat new multipart progressbar
This commit is contained in:
13 files changed
+216
-66
No files matched your search
+3
-1
@@ -153,4 +153,6 @@ dist
|
||||
|
||||
# Sentry Config File
|
||||
.sentryclirc
|
||||
.idea
|
||||
|
||||
# IDE specifics
|
||||
.idea
|
||||
Generated
+5
-4
@@ -6,7 +6,7 @@
|
||||
"": {
|
||||
"name": "@appwrite/console",
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "1.1.0",
|
||||
"@appwrite.io/console": "^1.2.0",
|
||||
"@appwrite.io/pink": "0.25.0",
|
||||
"@appwrite.io/pink-icons": "0.25.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
@@ -149,9 +149,10 @@
|
||||
"integrity": "sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg=="
|
||||
},
|
||||
"node_modules/@appwrite.io/console": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/console/-/console-1.1.0.tgz",
|
||||
"integrity": "sha512-jWg+NW9RJxh2pnE/14xwpXBcChiSLYBnG3Jkr5RnMJ1mH7BYmbAuLTyxFn3UFy5llB7jVq8pHNYGqA93ZoEMsQ=="
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/console/-/console-1.2.0.tgz",
|
||||
"integrity": "sha512-VglATKgjuhr9jYihz500VbqghOY/695aDwhXtx3beLMzvjjFK+eN+5BOgcNMTj01COl3kBu4wrvbXpDmVemStA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@appwrite.io/pink": {
|
||||
"version": "0.25.0",
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
"e2e:ui": "playwright test tests/e2e --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "1.1.0",
|
||||
"@appwrite.io/console": "^1.2.0",
|
||||
"@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.1.0
|
||||
version: 1.1.0
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
'@appwrite.io/pink':
|
||||
specifier: 0.25.0
|
||||
version: 0.25.0
|
||||
@@ -193,8 +193,8 @@ packages:
|
||||
'@analytics/type-utils@0.6.2':
|
||||
resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==}
|
||||
|
||||
'@appwrite.io/console@1.1.0':
|
||||
resolution: {integrity: sha512-jWg+NW9RJxh2pnE/14xwpXBcChiSLYBnG3Jkr5RnMJ1mH7BYmbAuLTyxFn3UFy5llB7jVq8pHNYGqA93ZoEMsQ==}
|
||||
'@appwrite.io/console@1.2.0':
|
||||
resolution: {integrity: sha512-VglATKgjuhr9jYihz500VbqghOY/695aDwhXtx3beLMzvjjFK+eN+5BOgcNMTj01COl3kBu4wrvbXpDmVemStA==}
|
||||
|
||||
'@appwrite.io/pink-icons@0.25.0':
|
||||
resolution: {integrity: sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q==}
|
||||
@@ -3697,7 +3697,7 @@ snapshots:
|
||||
|
||||
'@analytics/type-utils@0.6.2': {}
|
||||
|
||||
'@appwrite.io/console@1.1.0': {}
|
||||
'@appwrite.io/console@1.2.0': {}
|
||||
|
||||
'@appwrite.io/pink-icons@0.25.0': {}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ export { default as PaginationWithLimit } from './paginationWithLimit.svelte';
|
||||
export { default as ClickableList } from './clickableList.svelte';
|
||||
export { default as ClickableListItem } from './clickableListItem.svelte';
|
||||
export { default as Id } from './id.svelte';
|
||||
export { default as ProgressBar } from './progressBar.svelte';
|
||||
export * from './progressbar';
|
||||
export { default as ProgressBarBig } from './progressBarBig.svelte';
|
||||
export { default as CreditCardInfo } from './creditCardInfo.svelte';
|
||||
export { default as CreditCardBrandImage } from './creditCardBrandImage.svelte';
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
<script lang="ts">
|
||||
export let currentValue: string;
|
||||
export let currentUnit: string;
|
||||
export let maxValue: string;
|
||||
export let maxUnit: string;
|
||||
import { ProgressBar, type ProgressbarData } from '$lib/components/progressbar';
|
||||
|
||||
export let currentValue: string | undefined = undefined;
|
||||
export let currentUnit: string | undefined = undefined;
|
||||
export let maxValue: string | undefined = undefined;
|
||||
export let maxUnit: string | undefined = undefined;
|
||||
export let progressValue: number;
|
||||
export let progressMax: number;
|
||||
export let showBar = true;
|
||||
export let minimum = 0;
|
||||
export let maximum = 100;
|
||||
export let progressBarData: Array<ProgressbarData> = [];
|
||||
|
||||
$: progress = Math.round((progressValue / progressMax) * 100);
|
||||
</script>
|
||||
|
||||
<section class="progress-bar">
|
||||
<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>
|
||||
{#if currentValue !== undefined && currentUnit !== undefined && progress !== undefined && maxValue !== undefined && maxUnit !== 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>
|
||||
</div>
|
||||
|
||||
<p class="body-text-2">
|
||||
{maxValue}
|
||||
{maxUnit}
|
||||
</p>
|
||||
<p class="heading-level-4">{progress}%</p>
|
||||
</div>
|
||||
<p class="body-text-2">
|
||||
{maxValue}
|
||||
{maxUnit}
|
||||
</p>
|
||||
</div>
|
||||
{#if showBar}
|
||||
<div
|
||||
class="progress-bar-container u-margin-block-start-16"
|
||||
class:is-warning={progress >= 75 && progress < 100}
|
||||
class:is-danger={progress >= 100}
|
||||
style:--graph-size={Math.max(Math.min(progress, maximum), minimum) + '%'} />
|
||||
{/if}
|
||||
{#if showBar && progressBarData.length > 0}
|
||||
<ProgressBar maxSize={progressMax} data={progressBarData} />
|
||||
{/if}
|
||||
</section>
|
||||
File renamed without changes.
@@ -0,0 +1,92 @@
|
||||
<script lang="ts">
|
||||
import { tooltip } from '$lib/actions/tooltip';
|
||||
import type { ProgressbarData, ProgressbarProps } from '$lib/components';
|
||||
|
||||
type $$Props = ProgressbarProps;
|
||||
|
||||
/**
|
||||
* The max value of the progressbar
|
||||
*/
|
||||
export let maxSize: $$Props['maxSize'];
|
||||
|
||||
/**
|
||||
* The data for the progressbar
|
||||
*/
|
||||
export let data: $$Props['data'];
|
||||
|
||||
/**
|
||||
* The remaining value of the progressbar
|
||||
*/
|
||||
$: remainder = data.reduce((sum: number, item: ProgressbarData) => sum - item.size, maxSize);
|
||||
</script>
|
||||
|
||||
<section class="progressbar__container">
|
||||
{#each $$props.data as item}
|
||||
<div
|
||||
class="progressbar__content"
|
||||
style:background-color={item.color}
|
||||
style:width={`${(item.size / maxSize) * 100}%`}
|
||||
use:tooltip={{
|
||||
disabled: !item.tooltip,
|
||||
allowHTML: true,
|
||||
content: `<span class="u-bold">${item.tooltip.title}</span> ${item.tooltip.label}`
|
||||
}}>
|
||||
</div>
|
||||
{/each}
|
||||
{#if remainder > 0}
|
||||
<div class="progressbar__content" style:width={`${(remainder / maxSize) * 100}%`} />
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<style lang="scss">
|
||||
:root {
|
||||
--progressbar-border-radius: 0.25rem;
|
||||
--progressbar-tooltip-label-color: #818186;
|
||||
--progressbar-tooltip-link-color: #6c6c71;
|
||||
}
|
||||
|
||||
:global(.theme-dark) {
|
||||
--progressbar-background-color: var(--neutral-800, #2d2d31);
|
||||
--progressbar-tooltip-background-color: var(--neutral-800, #2d2d31);
|
||||
--progressbar-tooltip-border-color: var(--neutral-80, #424248);
|
||||
}
|
||||
:global(.theme-light) {
|
||||
--progressbar-background-color: var(--neutral-40, #f4f4f7);
|
||||
--progressbar-tooltip-background-color: #ffffff;
|
||||
--progressbar-tooltip-border-color: #ededf0;
|
||||
}
|
||||
|
||||
.progressbar {
|
||||
&__container {
|
||||
height: 0.5rem;
|
||||
background-color: var(--progressbar-background-color);
|
||||
border-radius: var(--progressbar-border-radius);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
&__content {
|
||||
height: 100%;
|
||||
min-width: 4px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
height: 2.5rem;
|
||||
margin-top: -1.25rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-left-radius: var(--progressbar-border-radius);
|
||||
border-bottom-left-radius: var(--progressbar-border-radius);
|
||||
}
|
||||
&:last-child {
|
||||
border-top-right-radius: var(--progressbar-border-radius);
|
||||
border-bottom-right-radius: var(--progressbar-border-radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,17 @@
|
||||
export type ProgressbarData = {
|
||||
size: number;
|
||||
color: string;
|
||||
tooltip?: {
|
||||
title: string;
|
||||
label: string;
|
||||
// linkTitle?: string;
|
||||
// linkPath?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type ProgressbarProps = {
|
||||
maxSize: number;
|
||||
data: Array<ProgressbarData>;
|
||||
};
|
||||
|
||||
export { default as ProgressBar } from './ProgressBar.svelte';
|
||||
@@ -178,6 +178,9 @@ export type OrganizationUsage = {
|
||||
bandwidth: Array<Models.Metric>;
|
||||
executions: Array<Models.Metric>;
|
||||
executionsTotal: number;
|
||||
filesStorageTotal: number;
|
||||
buildsStorageTotal: number;
|
||||
deploymentsStorageTotal: number;
|
||||
storageTotal: number;
|
||||
users: Array<Models.Metric>;
|
||||
usersTotal: number;
|
||||
|
||||
@@ -282,6 +282,32 @@
|
||||
{@const current = data.organizationUsage.storageTotal}
|
||||
{@const currentHumanized = humanFileSize(current)}
|
||||
{@const max = getServiceLimit('storage', tier)}
|
||||
{@const progressBarStorageDate = [
|
||||
{
|
||||
size: bytesToSize(data.organizationUsage.filesStorageTotal, 'GB'),
|
||||
color: '#85DBD8',
|
||||
tooltip: {
|
||||
title: 'File storage',
|
||||
label: `${Math.round(bytesToSize(data.organizationUsage.filesStorageTotal, 'GB') * 100) / 100}GB`
|
||||
}
|
||||
},
|
||||
{
|
||||
size: bytesToSize(data.organizationUsage.deploymentsStorageTotal, 'GB'),
|
||||
color: '#7C67FE',
|
||||
tooltip: {
|
||||
title: 'Deployments storage',
|
||||
label: `${Math.round(bytesToSize(data.organizationUsage.deploymentsStorageTotal, 'GB') * 100) / 100}GB`
|
||||
}
|
||||
},
|
||||
{
|
||||
size: bytesToSize(data.organizationUsage.buildsStorageTotal, 'GB'),
|
||||
color: '#FE9567',
|
||||
tooltip: {
|
||||
title: 'Builds storage',
|
||||
label: `${Math.round(bytesToSize(data.organizationUsage.buildsStorageTotal, 'GB') * 100) / 100}GB`
|
||||
}
|
||||
}
|
||||
]}
|
||||
<ProgressBarBig
|
||||
currentUnit={currentHumanized.unit}
|
||||
currentValue={currentHumanized.value}
|
||||
@@ -289,7 +315,7 @@
|
||||
maxValue={max.toString()}
|
||||
progressValue={bytesToSize(current, 'GB')}
|
||||
progressMax={max}
|
||||
minimum={1} />
|
||||
progressBarData={progressBarStorageDate} />
|
||||
{#if project?.length > 0}
|
||||
<ProjectBreakdown projects={project} metric="storage" {data} />
|
||||
{/if}
|
||||
|
||||
@@ -19,6 +19,9 @@ export const load: PageLoad = async ({ params, parent }) => {
|
||||
users: null,
|
||||
usersTotal: null,
|
||||
storageTotal: null,
|
||||
filesStorageTotal: null,
|
||||
buildsStorageTotal: null,
|
||||
deploymentsStorageTotal: null,
|
||||
executions: null,
|
||||
executionsTotal: null,
|
||||
projects: null
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { CardGrid, Heading, Card } from '$lib/components';
|
||||
import { CardGrid, Heading, Card, ProgressBarBig } from '$lib/components';
|
||||
import {
|
||||
TableBody,
|
||||
TableCell,
|
||||
@@ -13,7 +13,7 @@
|
||||
import { showUsageRatesModal, tierToPlan, upgradeURL } from '$lib/stores/billing';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { humanFileSize } from '$lib/helpers/sizeConvertion';
|
||||
import { bytesToSize, humanFileSize } from '$lib/helpers/sizeConvertion';
|
||||
import { BarChart } from '$lib/charts';
|
||||
import { formatNum } from '$lib/helpers/string';
|
||||
import { total } from '$lib/layout/usage.svelte';
|
||||
@@ -28,7 +28,10 @@
|
||||
$: usersTotal = data.usage.usersTotal;
|
||||
$: executions = data.usage.executions;
|
||||
$: executionsTotal = data.usage.executionsTotal;
|
||||
$: storage = data.usage.filesStorageTotal;
|
||||
$: storage =
|
||||
data.usage.filesStorageTotal +
|
||||
data.usage.deploymentsStorageTotal +
|
||||
data.usage.buildsStorageTotal;
|
||||
|
||||
const tier = data?.currentInvoice?.plan ?? $organization?.billingPlan;
|
||||
const plan = tierToPlan(tier).name;
|
||||
@@ -271,6 +274,32 @@
|
||||
<svelte:fragment slot="aside">
|
||||
{#if storage}
|
||||
{@const humanized = humanFileSize(storage)}
|
||||
{@const progressBarStorageDate = [
|
||||
{
|
||||
size: bytesToSize(data.usage.filesStorageTotal, 'MB'),
|
||||
color: '#85DBD8',
|
||||
tooltip: {
|
||||
title: 'File storage',
|
||||
label: `${Math.round(bytesToSize(data.usage.filesStorageTotal, 'MB') * 100) / 100}MB`
|
||||
}
|
||||
},
|
||||
{
|
||||
size: bytesToSize(data.usage.deploymentsStorageTotal, 'MB'),
|
||||
color: '#7C67FE',
|
||||
tooltip: {
|
||||
title: 'Deployments storage',
|
||||
label: `${Math.round(bytesToSize(data.usage.deploymentsStorageTotal, 'MB') * 100) / 100}MB`
|
||||
}
|
||||
},
|
||||
{
|
||||
size: bytesToSize(data.usage.buildsStorageTotal, 'MB'),
|
||||
color: '#FE9567',
|
||||
tooltip: {
|
||||
title: 'Builds storage',
|
||||
label: `${Math.round(bytesToSize(data.usage.buildsStorageTotal, 'MB') * 100) / 100}MB`
|
||||
}
|
||||
}
|
||||
]}
|
||||
<div class="u-flex u-flex-vertical">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<p>
|
||||
@@ -279,33 +308,10 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{#if data.usage.bucketsBreakdown.length > 0}
|
||||
<Table noMargin noStyles>
|
||||
<TableHeader>
|
||||
<TableCellHead width={285}>Bucket</TableCellHead>
|
||||
<TableCellHead>Usage</TableCellHead>
|
||||
<TableCellHead width={140} />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each data.usage.bucketsBreakdown.sort((a, b) => b.value - a.value) as bucket}
|
||||
{@const humanized = humanFileSize(bucket.value)}
|
||||
<TableRow>
|
||||
<TableCell title="Function">
|
||||
{bucket.name ?? bucket.resourceId}
|
||||
</TableCell>
|
||||
<TableCell title="Usage">
|
||||
{humanized.value}{humanized.unit}
|
||||
</TableCell>
|
||||
<TableCellLink
|
||||
href={`${baseRoute}/storage/bucket-${bucket.resourceId}`}
|
||||
title="View bucket">
|
||||
View bucket
|
||||
</TableCellLink>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{/if}
|
||||
<ProgressBarBig
|
||||
progressValue={bytesToSize(storage, 'MB')}
|
||||
progressMax={bytesToSize(storage, 'MB')}
|
||||
progressBarData={progressBarStorageDate} />
|
||||
{:else}
|
||||
<Card isDashed>
|
||||
<div class="u-flex u-cross-center u-flex-vertical u-main-center u-flex">
|
||||
|
||||
Reference in new issue
Block a user