Добавить переход в server UI и DEVNET topup

This commit is contained in:
AidarKC 2026-06-03 15:21:55 +04:00
parent d12371b84f
commit 4bd4df7b09
8 changed files with 71 additions and 3 deletions

View File

@ -0,0 +1,20 @@
# Кнопка настройки сервера и DEVNET topup
- краткое описание фичи:
На экране `entry-settings-view` добавлена кнопка `Настроить свой сервер`, открывающая `server-ui.html` в новой вкладке.
На страницах серверного UI добавлена кнопка открытия `devnet-topup-view` в новой вкладке с автоматической передачей `wallet` из device-адреса.
- что именно проверять:
1. На странице настроек входа есть кнопка `Настроить свой сервер`.
2. Кнопка открывает `shine-UI/server-ui.html` в новой вкладке.
3. На страницах `create-server-pda.html` и `update-server-pda.html` есть кнопка `Открыть пополнение DEVNET`.
4. Если device public key заполнен, новая вкладка открывает `devnet-topup-view?wallet=...` с правильным адресом.
5. Если device-адрес не введён, серверный UI показывает понятную ошибку и не открывает пустую ссылку.
- ожидаемый результат:
1. Переход в серверный UI с клиентской страницы настроек работает.
2. Пополнение devnet из серверного UI открывается сразу на нужный адрес.
3. Основной клиентский UI и серверные страницы не получают JS-ошибок при загрузке.
- статус:
pending

View File

@ -1,2 +1,2 @@
client.version=1.2.117 client.version=1.2.118
server.version=1.2.109 server.version=1.2.110

View File

@ -129,6 +129,15 @@ export function render({ navigate }) {
const actions = document.createElement('div'); const actions = document.createElement('div');
actions.className = 'auth-footer-actions'; actions.className = 'auth-footer-actions';
const serverUiButton = document.createElement('button');
serverUiButton.className = 'ghost-btn';
serverUiButton.type = 'button';
serverUiButton.textContent = 'Настроить свой сервер';
serverUiButton.addEventListener('click', () => {
const url = new URL('server-ui.html', window.location.href);
window.open(url.toString(), '_blank', 'noopener');
});
const cancelButton = document.createElement('button'); const cancelButton = document.createElement('button');
cancelButton.className = 'ghost-btn'; cancelButton.className = 'ghost-btn';
cancelButton.type = 'button'; cancelButton.type = 'button';
@ -144,7 +153,7 @@ export function render({ navigate }) {
navigate('start-view'); navigate('start-view');
}); });
actions.append(cancelButton, saveButton); actions.append(serverUiButton, cancelButton, saveButton);
const help = document.createElement('button'); const help = document.createElement('button');
help.className = 'help-fab'; help.className = 'help-fab';

View File

@ -28,6 +28,7 @@
.sol-ttl { font-size:12px; font-weight:600; color:#7dcc7d; } .sol-ttl { font-size:12px; font-weight:600; color:#7dcc7d; }
.sol-adr { font-family:monospace; font-size:12px; word-break:break-all; margin-top:4px; } .sol-adr { font-family:monospace; font-size:12px; word-break:break-all; margin-top:4px; }
.sol-ht { font-size:11px; color:var(--text-muted); margin-top:4px; } .sol-ht { font-size:11px; color:var(--text-muted); margin-top:4px; }
.sol-topup-btn { margin-top:10px; width:100%; }
</style> </style>
</head> </head>
<body> <body>
@ -112,6 +113,7 @@
<div class="sol-ttl">Положите SOL на этот адрес перед регистрацией:</div> <div class="sol-ttl">Положите SOL на этот адрес перед регистрацией:</div>
<div class="sol-adr" id="solAdr"></div> <div class="sol-adr" id="solAdr"></div>
<div class="sol-ht">Это Solana-адрес device-ключа (public key в base58 = Solana-адрес). С него оплачивается создание PDA.</div> <div class="sol-ht">Это Solana-адрес device-ключа (public key в base58 = Solana-адрес). С него оплачивается создание PDA.</div>
<button class="btn-secondary sol-topup-btn" id="btnTopupDevnet" type="button">Открыть пополнение DEVNET</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -4,6 +4,7 @@ import {
buildKeyBundleFromForm, buildKeyBundleFromForm,
clearGenMessage, clearGenMessage,
clearStatus, clearStatus,
openDevnetTopup,
deriveKeyBundleFromPassword, deriveKeyBundleFromPassword,
fillKeyFields, fillKeyFields,
parseLoginList, parseLoginList,
@ -30,6 +31,14 @@ const fieldMap = {
setupPasswordEye($('btnEye'), $('password')); setupPasswordEye($('btnEye'), $('password'));
wireDeviceAddressPreview(fieldMap); wireDeviceAddressPreview(fieldMap);
$('btnTopupDevnet').addEventListener('click', () => {
try {
openDevnetTopup($('devPub').value);
} catch (error) {
setStatus($('status'), error?.message || String(error), 'error');
}
});
$('btnGen').addEventListener('click', async () => { $('btnGen').addEventListener('click', async () => {
clearGenMessage($('genMsg')); clearGenMessage($('genMsg'));
clearStatus($('status')); clearStatus($('status'));

View File

@ -194,3 +194,20 @@ export function wireDeviceAddressPreview(fieldMap) {
$(fieldMap.devPub).addEventListener('input', update); $(fieldMap.devPub).addEventListener('input', update);
update(); update();
} }
export function buildDevnetTopupUrl(walletAddress) {
const cleanWallet = String(walletAddress || '').trim();
const url = new URL('../devnet-topup-view', window.location.href);
if (cleanWallet) {
url.searchParams.set('wallet', cleanWallet);
}
return url.toString();
}
export function openDevnetTopup(walletAddress) {
const cleanWallet = String(walletAddress || '').trim();
if (!cleanWallet) {
throw new Error('Сначала укажите device-адрес');
}
window.open(buildDevnetTopupUrl(cleanWallet), '_blank', 'noopener');
}

View File

@ -8,6 +8,7 @@ import {
fillKeyFields, fillKeyFields,
formatBigInt, formatBigInt,
formatTimestamp, formatTimestamp,
openDevnetTopup,
parseLoginList, parseLoginList,
setGenMessage, setGenMessage,
setStatus, setStatus,
@ -34,6 +35,14 @@ let currentPda = null;
setupPasswordEye($('btnEye'), $('password')); setupPasswordEye($('btnEye'), $('password'));
wireDeviceAddressPreview(fieldMap); wireDeviceAddressPreview(fieldMap);
$('btnTopupDevnet').addEventListener('click', () => {
try {
openDevnetTopup($('devPub').value);
} catch (error) {
setStatus($('status'), error?.message || String(error), 'error');
}
});
$('btnGen').addEventListener('click', async () => { $('btnGen').addEventListener('click', async () => {
clearGenMessage($('genMsg')); clearGenMessage($('genMsg'));
clearStatus($('status')); clearStatus($('status'));

View File

@ -29,6 +29,7 @@
.sol-adr { font-family:monospace; font-size:12px; word-break:break-all; margin-top:4px; } .sol-adr { font-family:monospace; font-size:12px; word-break:break-all; margin-top:4px; }
.sol-ht { font-size:11px; color:var(--text-muted); margin-top:4px; } .sol-ht { font-size:11px; color:var(--text-muted); margin-top:4px; }
.muted { font-size:12px; color:var(--text-muted); margin-bottom:14px; line-height:1.6; } .muted { font-size:12px; color:var(--text-muted); margin-bottom:14px; line-height:1.6; }
.sol-topup-btn { margin-top:10px; width:100%; }
</style> </style>
</head> </head>
<body> <body>
@ -126,6 +127,7 @@
<div class="sol-ttl">Положите SOL на этот адрес перед обновлением:</div> <div class="sol-ttl">Положите SOL на этот адрес перед обновлением:</div>
<div class="sol-adr" id="solAdr"></div> <div class="sol-adr" id="solAdr"></div>
<div class="sol-ht">Это Solana-адрес (base58) device-ключа. С него оплачивается транзакция.</div> <div class="sol-ht">Это Solana-адрес (base58) device-ключа. С него оплачивается транзакция.</div>
<button class="btn-secondary sol-topup-btn" id="btnTopupDevnet" type="button">Открыть пополнение DEVNET</button>
</div> </div>
</div> </div>
</div> </div>