feat: localize logs page
This commit is contained in:
+13
-13
@@ -34,12 +34,12 @@
|
|||||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6l4 4 4-4"/></svg>
|
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6l4 4 4-4"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<div class="ws-dropdown" id="ws-dropdown" style="display:none">
|
<div class="ws-dropdown" id="ws-dropdown" style="display:none">
|
||||||
<div class="ws-dropdown-label">Your workspaces</div>
|
<div class="ws-dropdown-label" data-i18n="nav.workspaces">Your workspaces</div>
|
||||||
<div id="ws-dropdown-list"></div>
|
<div id="ws-dropdown-list"></div>
|
||||||
<div class="ws-dropdown-footer">
|
<div class="ws-dropdown-footer">
|
||||||
<button class="ws-dropdown-create" onclick="window.location.href='/workspace-setup?mode=create'">
|
<button class="ws-dropdown-create" onclick="window.location.href='/workspace-setup?mode=create'">
|
||||||
<svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M8 3v10M3 8h10"/></svg>
|
<svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M8 3v10M3 8h10"/></svg>
|
||||||
Create workspace
|
<span data-i18n="nav.create_workspace">Create workspace</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
<svg width="12" height="12"><use href="icons/general/grid.svg#icon"/></svg>
|
<svg width="12" height="12"><use href="icons/general/grid.svg#icon"/></svg>
|
||||||
<span>⌘K</span>
|
<span>⌘K</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="nav-icon-btn" title="Notifications">
|
<button class="nav-icon-btn" data-i18n-title="nav.notifications" title="Notifications">
|
||||||
<svg width="15" height="15"><use href="icons/general/bell.svg#icon"/></svg>
|
<svg width="15" height="15"><use href="icons/general/bell.svg#icon"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<div class="nav-divider"></div>
|
<div class="nav-divider"></div>
|
||||||
@@ -96,27 +96,27 @@
|
|||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<div class="page-header-text">
|
<div class="page-header-text">
|
||||||
<h1 class="page-title" data-i18n="logs.title">Logs</h1>
|
<h1 class="page-title" data-i18n="logs.title">Logs</h1>
|
||||||
<p class="page-subtitle">Real-time invocation log for all operations in this workspace.</p>
|
<p class="page-subtitle" data-i18n="logs.subtitle">Real-time invocation log for all operations in this workspace.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="section-card">
|
<div class="section-card">
|
||||||
<div class="log-toolbar">
|
<div class="log-toolbar">
|
||||||
<div class="live-dot"></div>
|
<div class="live-dot"></div>
|
||||||
<span class="live-label">Live</span>
|
<span class="live-label" data-i18n="logs.live">Live</span>
|
||||||
<div class="toolbar-sep"></div>
|
<div class="toolbar-sep"></div>
|
||||||
|
|
||||||
<select class="time-range-select" id="time-range">
|
<select class="time-range-select" id="time-range">
|
||||||
<option value="30m">Last 30 min</option>
|
<option value="30m" data-i18n="logs.range.30m">Last 30 min</option>
|
||||||
<option value="1h" selected>Last 1 hour</option>
|
<option value="1h" selected data-i18n="logs.range.1h">Last 1 hour</option>
|
||||||
<option value="6h">Last 6 hours</option>
|
<option value="6h" data-i18n="logs.range.6h">Last 6 hours</option>
|
||||||
<option value="24h">Last 24 hours</option>
|
<option value="24h" data-i18n="logs.range.24h">Last 24 hours</option>
|
||||||
<option value="7d">Last 7 days</option>
|
<option value="7d" data-i18n="logs.range.7d">Last 7 days</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div class="toolbar-sep"></div>
|
<div class="toolbar-sep"></div>
|
||||||
|
|
||||||
<button class="filter-chip active" data-level="all" id="chip-all">All</button>
|
<button class="filter-chip active" data-level="all" id="chip-all" data-i18n="logs.level.all">All</button>
|
||||||
<button class="filter-chip" data-level="info" id="chip-info">
|
<button class="filter-chip" data-level="info" id="chip-info">
|
||||||
<span class="log-level info" style="padding:0 4px;font-size:10px;">INFO</span>
|
<span class="log-level info" style="padding:0 4px;font-size:10px;">INFO</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -129,12 +129,12 @@
|
|||||||
|
|
||||||
<div class="filter-bar-search" style="max-width:240px;margin:0;">
|
<div class="filter-bar-search" style="max-width:240px;margin:0;">
|
||||||
<svg width="13" height="13" style="position:absolute;left:9px;top:50%;transform:translateY(-50%);color:var(--text-muted);" viewBox="0 0 16 16" fill="currentColor"><path d="M10.68 11.74a6 6 0 01-7.922-8.982 6 6 0 018.982 7.922l3.04 3.04a.749.749 0 01-.326 1.275.749.749 0 01-.734-.215zM11.5 7a4.499 4.499 0 11-8.997 0A4.499 4.499 0 0111.5 7z"/></svg>
|
<svg width="13" height="13" style="position:absolute;left:9px;top:50%;transform:translateY(-50%);color:var(--text-muted);" viewBox="0 0 16 16" fill="currentColor"><path d="M10.68 11.74a6 6 0 01-7.922-8.982 6 6 0 018.982 7.922l3.04 3.04a.749.749 0 01-.326 1.275.749.749 0 01-.734-.215zM11.5 7a4.499 4.499 0 11-8.997 0A4.499 4.499 0 0111.5 7z"/></svg>
|
||||||
<input type="text" id="log-search" placeholder="Search messages…" autocomplete="off">
|
<input type="text" id="log-search" data-i18n-ph="logs.search_messages" placeholder="Search messages…" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="refresh-btn" id="refresh-btn" type="button">
|
<button class="refresh-btn" id="refresh-btn" type="button">
|
||||||
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor"><path d="M1.705 8.005a.75.75 0 01.834.656 5.5 5.5 0 009.592 2.97l-1.204-1.204a.25.25 0 01.177-.427h3.646a.25.25 0 01.25.25v3.646a.25.25 0 01-.427.177l-1.38-1.38A7.001 7.001 0 011.05 8.84a.75.75 0 01.656-.834zM8 2.5a5.487 5.487 0 00-4.131 1.869l1.204 1.204A.25.25 0 014.896 6H1.25A.25.25 0 011 5.75V2.104a.25.25 0 01.427-.177l1.38 1.38A7.001 7.001 0 0114.95 7.16a.75.75 0 01-1.49.178A5.501 5.501 0 008 2.5z"/></svg>
|
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor"><path d="M1.705 8.005a.75.75 0 01.834.656 5.5 5.5 0 009.592 2.97l-1.204-1.204a.25.25 0 01.177-.427h3.646a.25.25 0 01.25.25v3.646a.25.25 0 01-.427.177l-1.38-1.38A7.001 7.001 0 011.05 8.84a.75.75 0 01.656-.834zM8 2.5a5.487 5.487 0 00-4.131 1.869l1.204 1.204A.25.25 0 014.896 6H1.25A.25.25 0 011 5.75V2.104a.25.25 0 01.427-.177l1.38 1.38A7.001 7.001 0 0114.95 7.16a.75.75 0 01-1.49.178A5.501 5.501 0 008 2.5z"/></svg>
|
||||||
Refresh
|
<span data-i18n="logs.refresh">Refresh</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+58
-2
@@ -155,13 +155,41 @@ var TRANSLATIONS = {
|
|||||||
|
|
||||||
// Logs page
|
// Logs page
|
||||||
'logs.title': 'Logs',
|
'logs.title': 'Logs',
|
||||||
'logs.subtitle': 'Real-time request and event log',
|
'logs.subtitle': 'Real-time invocation log for all operations in this workspace.',
|
||||||
'logs.search': 'Search logs...',
|
'logs.search': 'Search logs...',
|
||||||
'logs.level.all': 'All',
|
'logs.level.all': 'All',
|
||||||
'logs.level.info': 'Info',
|
'logs.level.info': 'Info',
|
||||||
'logs.level.warn': 'Warn',
|
'logs.level.warn': 'Warn',
|
||||||
'logs.level.error': 'Error',
|
'logs.level.error': 'Error',
|
||||||
'logs.level.debug': 'Debug',
|
'logs.level.debug': 'Debug',
|
||||||
|
'logs.live': 'Live',
|
||||||
|
'logs.paused': 'Paused',
|
||||||
|
'logs.refresh': 'Refresh',
|
||||||
|
'logs.range.30m': 'Last 30 min',
|
||||||
|
'logs.range.1h': 'Last 1 hour',
|
||||||
|
'logs.range.6h': 'Last 6 hours',
|
||||||
|
'logs.range.24h': 'Last 24 hours',
|
||||||
|
'logs.range.7d': 'Last 7 days',
|
||||||
|
'logs.search_messages': 'Search messages…',
|
||||||
|
'logs.detail.agent': 'Agent',
|
||||||
|
'logs.detail.request': 'Request preview',
|
||||||
|
'logs.detail.response': 'Response preview',
|
||||||
|
'logs.detail.meta': 'Metadata',
|
||||||
|
'logs.loading.title': 'Loading logs…',
|
||||||
|
'logs.loading.sub': 'Fetching invocation history for the current workspace.',
|
||||||
|
'logs.error.title': 'Unable to load logs',
|
||||||
|
'logs.error.api': 'Admin API is not available',
|
||||||
|
'logs.error.workspace': 'Workspace is not selected',
|
||||||
|
'logs.error.load': 'Failed to load logs',
|
||||||
|
'logs.empty.title': 'No log entries found',
|
||||||
|
'logs.empty.filtered': 'Try widening the period or clearing the current search and level filters.',
|
||||||
|
'logs.empty.initial': 'Run tests or published MCP tools to start collecting invocation history.',
|
||||||
|
'logs.live.on.title': 'Live mode enabled',
|
||||||
|
'logs.live.on.body': 'Polling logs every 4 seconds.',
|
||||||
|
'logs.live.off.title': 'Live mode paused',
|
||||||
|
'logs.live.off.body': 'Automatic polling is paused.',
|
||||||
|
'logs.refresh.title': 'Logs refreshed',
|
||||||
|
'logs.refresh.body': 'The latest invocation records were loaded for the current workspace.',
|
||||||
|
|
||||||
// Usage page
|
// Usage page
|
||||||
'usage.title': 'Usage',
|
'usage.title': 'Usage',
|
||||||
@@ -446,13 +474,41 @@ var TRANSLATIONS = {
|
|||||||
|
|
||||||
// Logs page
|
// Logs page
|
||||||
'logs.title': 'Логи',
|
'logs.title': 'Логи',
|
||||||
'logs.subtitle': 'Журнал запросов и событий в реальном времени',
|
'logs.subtitle': 'Живой журнал вызовов по всем операциям этого воркспейса.',
|
||||||
'logs.search': 'Поиск в логах...',
|
'logs.search': 'Поиск в логах...',
|
||||||
'logs.level.all': 'Все',
|
'logs.level.all': 'Все',
|
||||||
'logs.level.info': 'Info',
|
'logs.level.info': 'Info',
|
||||||
'logs.level.warn': 'Warn',
|
'logs.level.warn': 'Warn',
|
||||||
'logs.level.error': 'Error',
|
'logs.level.error': 'Error',
|
||||||
'logs.level.debug': 'Debug',
|
'logs.level.debug': 'Debug',
|
||||||
|
'logs.live': 'Live',
|
||||||
|
'logs.paused': 'Пауза',
|
||||||
|
'logs.refresh': 'Обновить',
|
||||||
|
'logs.range.30m': 'Последние 30 мин',
|
||||||
|
'logs.range.1h': 'Последний 1 час',
|
||||||
|
'logs.range.6h': 'Последние 6 часов',
|
||||||
|
'logs.range.24h': 'Последние 24 часа',
|
||||||
|
'logs.range.7d': 'Последние 7 дней',
|
||||||
|
'logs.search_messages': 'Поиск по сообщениям…',
|
||||||
|
'logs.detail.agent': 'Агент',
|
||||||
|
'logs.detail.request': 'Предпросмотр запроса',
|
||||||
|
'logs.detail.response': 'Предпросмотр ответа',
|
||||||
|
'logs.detail.meta': 'Метаданные',
|
||||||
|
'logs.loading.title': 'Загрузка логов…',
|
||||||
|
'logs.loading.sub': 'Получаем историю вызовов для текущего воркспейса.',
|
||||||
|
'logs.error.title': 'Не удалось загрузить логи',
|
||||||
|
'logs.error.api': 'Admin API недоступен',
|
||||||
|
'logs.error.workspace': 'Воркспейс не выбран',
|
||||||
|
'logs.error.load': 'Не удалось загрузить логи',
|
||||||
|
'logs.empty.title': 'Записей логов не найдено',
|
||||||
|
'logs.empty.filtered': 'Попробуйте расширить период или сбросить текущий поиск и фильтры уровня.',
|
||||||
|
'logs.empty.initial': 'Запустите тесты или опубликованные MCP-инструменты, чтобы начать собирать историю вызовов.',
|
||||||
|
'logs.live.on.title': 'Live режим включен',
|
||||||
|
'logs.live.on.body': 'Логи опрашиваются каждые 4 секунды.',
|
||||||
|
'logs.live.off.title': 'Live режим на паузе',
|
||||||
|
'logs.live.off.body': 'Автоматический опрос остановлен.',
|
||||||
|
'logs.refresh.title': 'Логи обновлены',
|
||||||
|
'logs.refresh.body': 'Получены последние записи вызовов для текущего воркспейса.',
|
||||||
|
|
||||||
// Usage page
|
// Usage page
|
||||||
'usage.title': 'Использование',
|
'usage.title': 'Использование',
|
||||||
|
|||||||
+20
-16
@@ -20,6 +20,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
var liveDot = document.querySelector('.live-dot');
|
var liveDot = document.querySelector('.live-dot');
|
||||||
var liveLabel = document.querySelector('.live-label');
|
var liveLabel = document.querySelector('.live-label');
|
||||||
|
|
||||||
|
function tKey(key) {
|
||||||
|
return window.t ? t(key) : key;
|
||||||
|
}
|
||||||
|
|
||||||
function currentWorkspaceId() {
|
function currentWorkspaceId() {
|
||||||
var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null;
|
var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null;
|
||||||
return workspace ? workspace.id : null;
|
return workspace ? workspace.id : null;
|
||||||
@@ -98,21 +102,21 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
|
|
||||||
function renderLogs() {
|
function renderLogs() {
|
||||||
if (state.loading && state.logs.length === 0) {
|
if (state.loading && state.logs.length === 0) {
|
||||||
renderEmpty('Loading logs…', 'Fetching invocation history for the current workspace.');
|
renderEmpty(tKey('logs.loading.title'), tKey('logs.loading.sub'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.loadError) {
|
if (state.loadError) {
|
||||||
renderEmpty('Unable to load logs', state.loadError);
|
renderEmpty(tKey('logs.error.title'), state.loadError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state.logs.length) {
|
if (!state.logs.length) {
|
||||||
renderEmpty(
|
renderEmpty(
|
||||||
'No log entries found',
|
tKey('logs.empty.title'),
|
||||||
state.search || state.level !== 'all'
|
state.search || state.level !== 'all'
|
||||||
? 'Try widening the period or clearing the current search and level filters.'
|
? tKey('logs.empty.filtered')
|
||||||
: 'Run tests or published MCP tools to start collecting invocation history.'
|
: tKey('logs.empty.initial')
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -172,7 +176,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
if (detail.agentDisplayName || detail.agentSlug) {
|
if (detail.agentDisplayName || detail.agentSlug) {
|
||||||
var agentLabel = document.createElement('div');
|
var agentLabel = document.createElement('div');
|
||||||
agentLabel.className = 'log-detail-label';
|
agentLabel.className = 'log-detail-label';
|
||||||
agentLabel.textContent = 'Agent';
|
agentLabel.textContent = tKey('logs.detail.agent');
|
||||||
expanded.appendChild(agentLabel);
|
expanded.appendChild(agentLabel);
|
||||||
|
|
||||||
var agentPre = document.createElement('pre');
|
var agentPre = document.createElement('pre');
|
||||||
@@ -183,7 +187,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
|
|
||||||
var requestLabel = document.createElement('div');
|
var requestLabel = document.createElement('div');
|
||||||
requestLabel.className = 'log-detail-label';
|
requestLabel.className = 'log-detail-label';
|
||||||
requestLabel.textContent = 'Request preview';
|
requestLabel.textContent = tKey('logs.detail.request');
|
||||||
expanded.appendChild(requestLabel);
|
expanded.appendChild(requestLabel);
|
||||||
|
|
||||||
var requestPre = document.createElement('pre');
|
var requestPre = document.createElement('pre');
|
||||||
@@ -193,7 +197,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
|
|
||||||
var responseLabel = document.createElement('div');
|
var responseLabel = document.createElement('div');
|
||||||
responseLabel.className = 'log-detail-label';
|
responseLabel.className = 'log-detail-label';
|
||||||
responseLabel.textContent = 'Response preview';
|
responseLabel.textContent = tKey('logs.detail.response');
|
||||||
expanded.appendChild(responseLabel);
|
expanded.appendChild(responseLabel);
|
||||||
|
|
||||||
var responsePre = document.createElement('pre');
|
var responsePre = document.createElement('pre');
|
||||||
@@ -204,7 +208,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
if (detail.errorKind || detail.requestId) {
|
if (detail.errorKind || detail.requestId) {
|
||||||
var metaLabel = document.createElement('div');
|
var metaLabel = document.createElement('div');
|
||||||
metaLabel.className = 'log-detail-label';
|
metaLabel.className = 'log-detail-label';
|
||||||
metaLabel.textContent = 'Metadata';
|
metaLabel.textContent = tKey('logs.detail.meta');
|
||||||
expanded.appendChild(metaLabel);
|
expanded.appendChild(metaLabel);
|
||||||
|
|
||||||
var metaPre = document.createElement('pre');
|
var metaPre = document.createElement('pre');
|
||||||
@@ -253,14 +257,14 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
|
|
||||||
async function loadLogs() {
|
async function loadLogs() {
|
||||||
if (!window.CrankApi) {
|
if (!window.CrankApi) {
|
||||||
state.loadError = 'Admin API is not available';
|
state.loadError = tKey('logs.error.api');
|
||||||
renderLogs();
|
renderLogs();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.workspaceId = currentWorkspaceId();
|
state.workspaceId = currentWorkspaceId();
|
||||||
if (!state.workspaceId) {
|
if (!state.workspaceId) {
|
||||||
state.loadError = 'Workspace is not selected';
|
state.loadError = tKey('logs.error.workspace');
|
||||||
renderLogs();
|
renderLogs();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -276,7 +280,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
state.openId = null;
|
state.openId = null;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
state.loadError = error.message || 'Failed to load logs';
|
state.loadError = error.message || tKey('logs.error.load');
|
||||||
} finally {
|
} finally {
|
||||||
state.loading = false;
|
state.loading = false;
|
||||||
renderLogs();
|
renderLogs();
|
||||||
@@ -305,7 +309,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
liveDot.style.cursor = 'pointer';
|
liveDot.style.cursor = 'pointer';
|
||||||
}
|
}
|
||||||
if (liveLabel) {
|
if (liveLabel) {
|
||||||
liveLabel.textContent = state.liveMode ? 'Live' : 'Paused';
|
liveLabel.textContent = state.liveMode ? tKey('logs.live') : tKey('logs.paused');
|
||||||
liveLabel.style.color = state.liveMode ? '' : 'var(--text-muted)';
|
liveLabel.style.color = state.liveMode ? '' : 'var(--text-muted)';
|
||||||
liveLabel.style.cursor = 'pointer';
|
liveLabel.style.cursor = 'pointer';
|
||||||
}
|
}
|
||||||
@@ -332,8 +336,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
startPolling();
|
startPolling();
|
||||||
if (window.CrankUi) {
|
if (window.CrankUi) {
|
||||||
window.CrankUi.info(
|
window.CrankUi.info(
|
||||||
state.liveMode ? 'Polling logs every 4 seconds.' : 'Automatic polling is paused.',
|
state.liveMode ? tKey('logs.live.on.body') : tKey('logs.live.off.body'),
|
||||||
state.liveMode ? 'Live mode enabled' : 'Live mode paused'
|
state.liveMode ? tKey('logs.live.on.title') : tKey('logs.live.off.title')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,7 +364,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
refreshBtn.addEventListener('click', function () {
|
refreshBtn.addEventListener('click', function () {
|
||||||
loadLogs().then(function () {
|
loadLogs().then(function () {
|
||||||
if (!state.loadError && window.CrankUi) {
|
if (!state.loadError && window.CrankUi) {
|
||||||
window.CrankUi.info('The latest invocation records were loaded for the current workspace.', 'Logs refreshed');
|
window.CrankUi.info(tKey('logs.refresh.body'), tKey('logs.refresh.title'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user