Criar "lucas@cienciaembarcada.com.br" criava "lucas@lucasrguerra.dev.br". O formulario partia o endereco e deitava fora a metade do dominio, e nao enviava domain_id nenhum -- o servidor caia entao no dominio do admin com sessao iniciada. Passa a ser parte local mais um dominio escolhido de uma lista: a metade que decide o endereco deixa de poder ser descartada em silencio. Apelidos de outros dominios estavam escondidos, e a culpa era minha: procurava so no dominio onde a morada do proprio utilizador vive. Uma caixa recebe postmaster, abuse, dmarc e tlsrpt de varios dominios ao mesmo tempo, por isso o painel mostrava quatro onde entregavam oito. Ha um teste que falha com a consulta antiga. Os apelidos passam a poder ser criados e removidos dentro do modal. O dominio sai do endereco escrito, para nao repetir a armadilha do formulario de cima. USER, DOMAIN_ADMIN e SUPER_ADMIN eram constantes impressas no ecra, logo ficavam em ingles em qualquer idioma. Um papel desconhecido continua a ser mostrado tal como esta guardado, porque quem o ve precisa de saber o que a base de dados tem. A quota estava certa e mal mostrada. used_bytes vale 140771 -- os 137,5 KB reais -- mas a pagina arredondava para megabytes inteiros, portanto qualquer coisa abaixo de 512 KB lia-se "0 / 2 MB" e a barra ficava vazia, calculada sobre os megabytes ja arredondados. Passa a formatar a partir dos bytes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
39 lines
1.4 KiB
TypeScript
39 lines
1.4 KiB
TypeScript
/**
|
|
* A byte count as a person reads it.
|
|
*
|
|
* The admin list rounded bytes to whole megabytes, so a mailbox holding
|
|
* 137.5 KB displayed as "0 / 2 MB" and its usage bar sat empty - the figure
|
|
* was right in the database and lost on the way to the screen.
|
|
*/
|
|
export function formatBytes(bytes: number): string {
|
|
const value = Number(bytes);
|
|
if (!Number.isFinite(value) || value <= 0) return "0 B";
|
|
|
|
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
let n = value;
|
|
let unit = 0;
|
|
while (n >= 1024 && unit < units.length - 1) {
|
|
n /= 1024;
|
|
unit++;
|
|
}
|
|
|
|
// Bytes are whole things; above that always one decimal, which is what
|
|
// tells 137.5 KB from 137 KB. Dropping it on larger numbers would have hid
|
|
// exactly the digit that made the reading recognisable.
|
|
const rendered = unit === 0 ? String(Math.round(n)) : n.toFixed(1);
|
|
return `${rendered} ${units[unit]}`;
|
|
}
|
|
|
|
/**
|
|
* How full a mailbox is, as a percentage, computed from the raw byte counts.
|
|
*
|
|
* A quota of zero means unlimited, so it is never full - dividing by it would
|
|
* report every unlimited mailbox as over its limit.
|
|
*/
|
|
export function usageRatio(usedBytes: number, quotaBytes: number): number {
|
|
const used = Number(usedBytes);
|
|
const quota = Number(quotaBytes);
|
|
if (!Number.isFinite(used) || !Number.isFinite(quota) || quota <= 0 || used <= 0) return 0;
|
|
return Math.min(used / quota, 1);
|
|
}
|