merged from gramsrv upstream

This commit is contained in:
onysd 2026-09-01 12:06:31 +03:00
parent 79c64ee916
commit 21a0856587
651 changed files with 54774 additions and 4590 deletions

View file

@ -23,8 +23,8 @@
})();
</script>
<script type="module" crossorigin src="/assets/index-D8u51wND.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-hA2EpjuH.css">
<script type="module" crossorigin src="/assets/index-CwTwvGWj.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-0MvM-hpw.css">
</head>
<body>
<div id="root"></div>

View file

@ -758,9 +758,9 @@
}
},
"node_modules/nanoid": {
"version": "3.3.16",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
"version": "3.3.18",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
"integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
"dev": true,
"funding": [
{

View file

@ -193,3 +193,20 @@ export function parseIDs(value: string, invalidMessage = "msg ids invalid"): num
}
return ids;
}
// toUnixSeconds reads a datetime-local input. Such an input carries no zone, so
// the value parses as the operator's local time — which is the time they picked.
// 0 means "empty or unparseable", which every caller treats as "not scheduled".
export function toUnixSeconds(value: string): number {
if (!value.trim()) return 0;
const ms = new Date(value).getTime();
return Number.isFinite(ms) ? Math.floor(ms / 1000) : 0;
}
// localInputValue formats a datetime-local default some seconds out, so a
// scheduling form never opens on a value the server would reject as past.
export function localInputValue(offsetSeconds: number): string {
const at = new Date(Date.now() + offsetSeconds * 1000);
const pad = (n: number) => String(n).padStart(2, "0");
return `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}T${pad(at.getHours())}:${pad(at.getMinutes())}`;
}

View file

@ -166,7 +166,7 @@ export function ownerLabel(row: CollectibleUsernameRow, vaultLabel: string): str
export function priceLabel(row: CollectibleUsernameRow): string {
const base = formatCurrency(row.Amount, row.Currency);
if (row.CryptoCurrency && row.CryptoAmount && row.CryptoAmount !== "0") {
return `${base} (${formatCurrency(row.CryptoAmount, row.CryptoCurrency)})`;
return `${formatCurrency(row.CryptoAmount, row.CryptoCurrency)} (${base})`;
}
return base;
}

View file

@ -5,6 +5,8 @@ import { Alert, PageFrame } from "./components/ui";
// (cmd/telesrv-admin/security.go). "*" is the wildcard an operator configures for
// a full-access session.
export const permissionAll = "*";
export const permissionPremiumManage = "premium.manage";
export const permissionBotTokenRead = "bots.token.read";
export const permissionVerificationReview = "verification.review";
export const permissionVerificationRevoke = "verification.revoke";
// Third-party verification is a separate mechanism and therefore a separate pair of

View file

@ -425,3 +425,34 @@
transform: rotate(360deg);
}
}
.secret-reveal {
display: grid;
gap: 6px;
padding: 10px;
background: var(--warn-tint);
border: 1px solid var(--warn-border);
border-radius: var(--radius);
}
.secret-reveal-label {
display: flex;
align-items: center;
gap: 6px;
color: var(--warn);
font-size: 12px;
font-weight: 800;
}
.secret-reveal-row { display: flex; align-items: center; gap: 10px; }
.secret-reveal-value {
overflow: hidden;
flex: 1 1 auto;
padding: 6px 10px;
color: var(--text-soft);
letter-spacing: .12em;
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--radius-sm);
text-overflow: ellipsis;
white-space: nowrap;
}