pf-sdn/webui/src/ui/api_tokens.js

205 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import $ from 'jquery';
import { JSONRPC } from '@/json-rpc.js';
// --- Глобальное состояние ---
let tokens = [];
/**
* @private
* Загружает текущий список токенов.
* @returns {Promise<boolean>}
*/
async function loadTokens() {
try {
// Запрос списка токенов
tokens = await JSONRPC.Auth.listTokens();
tokens = tokens || [];
return true;
} catch (e) {
console.error("Ошибка при загрузке токенов:", e);
tokens = [];
return false;
}
}
/**
* @private
* Рендерит список токенов и кнопки управления.
*/
function renderTokenList() {
const $listContainer = $('#api-token-container');
// Кнопка "Создать токен"
const createButtonHtml = `
<button id="create-token-btn" class="btn-primary" style="width: 200px; margin-bottom: 30px;">
Создать токен API
</button>
<div id="token-status-message" class="success-message" style="display: none;"></div>
`;
if (tokens.length === 0) {
$listContainer.html(createButtonHtml + '<p>Активных API токенов не найдено.</p>');
attachEventHandlers();
return;
}
let listHtml = tokens.map(item => {
// Мы НЕ показываем полный токен, показываем только его начало/конец для идентификации
const displayToken = item.token ?
`${item.token.substring(0, 8)}...${item.token.substring(item.token.length - 4)}` :
'Неизвестный токен';
return `
<li class="token-item" data-full-token="${item.token}">
<div class="token-description">${item.description}</div>
<div class="token-details">
<span class="token-value">Ключ: ${displayToken}</span>
<button class="delete-token-btn btn-icon" data-token="${item.token}" title="Удалить токен">
<span class="delete-icon">✖</span>
</button>
</div>
</li>
`;
}).join('');
const html = `
${createButtonHtml}
<ul class="token-list">${listHtml}</ul>
`;
$listContainer.html(html);
attachEventHandlers();
}
/**
* @private
* Отображает модальное окно для создания токена.
*/
function showCreateTokenModal() {
// Используем простое модальное окно jQuery для минимализма
const description = prompt("Введите описание для нового API токена (например, 'Токен для Telegram бота'):");
if (description === null) {
return; // Пользователь нажал Отмена
}
if (description.trim() === "") {
alert("Описание токена не может быть пустым.");
return;
}
createToken(description.trim());
}
/**
* @private
* Логика создания токена и обновления UI.
* @param {string} description - Описание токена.
*/
async function createToken(description) {
const $btn = $('#create-token-btn');
const $message = $('#token-status-message');
$message.hide().removeClass('error-message').addClass('success-message');
$btn.prop('disabled', true).text('Создание...');
try {
const newTokenValue = await JSONRPC.Auth.createAPIToken(description);
if (!newTokenValue) {
throw new Error("Сервер не вернул токен.");
}
// Показываем токен пользователю ОДИН раз
prompt("ВАЖНО: Ваш новый токен API. Сохраните его, он больше не будет показан!", newTokenValue);
// Перезагружаем список
await loadTokens();
renderTokenList();
$message.text(`Токен "${description}" успешно создан.`).show();
} catch (e) {
console.error('Ошибка создания токена:', e);
$message.removeClass('success-message').addClass('error-message').text('Ошибка при создании токена.').show();
} finally {
$btn.prop('disabled', false).text('Создать токен API');
setTimeout(() => $message.fadeOut(), 8000);
}
}
/**
* @private
* Логика удаления токена.
* @param {string} token - Токен для удаления.
*/
async function deleteToken(token) {
if (!confirm("Вы уверены, что хотите удалить этот API токен?")) {
return;
}
const $item = $(`li.token-item[data-full-token="${token}"]`);
$item.addClass('deleting').css('opacity', 0.5); // Визуальная обратная связь
try {
await JSONRPC.Auth.removeToken(token);
// Удаляем из локального состояния
tokens = tokens.filter(item => item.token !== token);
// Перерисовываем список
renderTokenList();
const $message = $('#token-status-message');
$message.text('Токен успешно удален.').addClass('success-message').show();
} catch (e) {
console.error('Ошибка удаления токена:', e);
$item.removeClass('deleting').css('opacity', 1); // Восстанавливаем, если ошибка
const $message = $('#token-status-message');
$message.removeClass('success-message').addClass('error-message').text('Ошибка при удалении токена.').show();
}
}
/**
* @private
* Прикрепление обработчиков событий.
*/
function attachEventHandlers() {
$('#create-token-btn').off('click').on('click', showCreateTokenModal);
// Делегирование для кнопок удаления (они перерисовываются)
$('#api-token-container').off('click', '.delete-token-btn').on('click', '.delete-token-btn', function() {
const tokenToDelete = $(this).data('token');
if (tokenToDelete) {
deleteToken(tokenToDelete);
}
});
}
// --- Функции для роутера ---
export const APITokensPage = {
render: () => {
return `
<h1 class="page-title">API Токены</h1>
<div id="api-token-container">
<p>Загрузка токенов...</p>
</div>
`;
},
mount: async () => {
const success = await loadTokens();
if (success) {
renderTokenList();
} else {
$('#api-token-container').html('<p class="error-message">Не удалось загрузить токены. Проверьте соединение с сервером.</p>');
}
},
unmount: () => {
tokens = [];
$('#api-token-container').off(); // Удаляем все обработчики
}
};