Files
BetterDesk/web-nodejs/views/server-management.ejs
T
UNITRONIX a8d3259d43 feat(server-management): add server management service and terminal proxy
- Implemented server management service providing resource snapshots, file browser, service control, and audit logging.
- Added terminal proxy for WebSocket-backed PTY, allowing browser-based shell access with user authentication and role-based access control.
- Created server management view with tabs for overview, terminal, file management, and services, including UI elements for displaying system metrics and managing files/services.

Co-authored-by: Copilot <copilot@github.com>
2026-05-07 03:09:03 +02:00

215 lines
12 KiB
HTML
Raw Permalink 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.
<% var initialTab = (typeof currentTab !== 'undefined' && currentTab) ? currentTab : 'overview'; %>
<%- include('layouts/main', {
title: _('server_mgmt.title'),
pageStyles: ['server-management'],
pageScripts: ['server-management'],
currentPage: 'server-management',
currentTab: initialTab,
widePage: true,
breadcrumb: [{ label: _('server_mgmt.title') }],
body: `
<div class="server-mgmt-page" id="server-mgmt-page" data-initial-tab="${initialTab}">
<!-- Header -->
<div class="page-header server-mgmt-header">
<div class="page-title">
<h1>
<span class="material-icons">dns</span>
${_('server_mgmt.title')}
<span class="beta-badge" title="${_('server_mgmt.beta_tooltip')}">BETA</span>
</h1>
</div>
<p class="page-subtitle">${_('server_mgmt.subtitle')}</p>
</div>
<!-- Beta notice -->
<div class="server-mgmt-notice">
<span class="material-icons">info</span>
<div>
<strong>${_('server_mgmt.notice_title')}</strong>
<p>${_('server_mgmt.notice_body')}</p>
</div>
</div>
<div class="server-mgmt-layout">
<div class="server-mgmt-content">
<!-- Overview tab -->
<section class="sm-tab-panel active" id="sm-panel-overview" role="tabpanel">
<div class="sm-overview-grid">
<div class="sm-card">
<div class="sm-card-header">
<span class="material-icons">memory</span>
<h3>${_('server_mgmt.cpu')}</h3>
</div>
<div class="sm-gauge" id="sm-cpu-gauge">
<div class="sm-gauge-bar"><div class="sm-gauge-fill" id="sm-cpu-fill"></div></div>
<div class="sm-gauge-value" id="sm-cpu-value">0%</div>
</div>
<div class="sm-meta" id="sm-cpu-meta"></div>
</div>
<div class="sm-card">
<div class="sm-card-header">
<span class="material-icons">developer_board</span>
<h3>${_('server_mgmt.memory')}</h3>
</div>
<div class="sm-gauge">
<div class="sm-gauge-bar"><div class="sm-gauge-fill" id="sm-mem-fill"></div></div>
<div class="sm-gauge-value" id="sm-mem-value">0%</div>
</div>
<div class="sm-meta" id="sm-mem-meta"></div>
</div>
<div class="sm-card">
<div class="sm-card-header">
<span class="material-icons">speed</span>
<h3>${_('server_mgmt.load')}</h3>
</div>
<div class="sm-load-row">
<div><span class="sm-stat-label">1m</span><span id="sm-load-1"></span></div>
<div><span class="sm-stat-label">5m</span><span id="sm-load-5"></span></div>
<div><span class="sm-stat-label">15m</span><span id="sm-load-15"></span></div>
</div>
<div class="sm-meta" id="sm-uptime-meta"></div>
</div>
<div class="sm-card sm-card-wide">
<div class="sm-card-header">
<span class="material-icons">storage</span>
<h3>${_('server_mgmt.disks')}</h3>
</div>
<div id="sm-disks"></div>
</div>
<div class="sm-card sm-card-wide">
<div class="sm-card-header">
<span class="material-icons">timeline</span>
<h3>${_('server_mgmt.history')}</h3>
</div>
<div class="sm-history-wrap">
<canvas id="sm-history-chart" height="120"></canvas>
<div class="sm-history-legend">
<span><span class="dot dot-cpu"></span>${_('server_mgmt.cpu')}</span>
<span><span class="dot dot-mem"></span>${_('server_mgmt.memory')}</span>
</div>
</div>
</div>
<div class="sm-card sm-card-wide">
<div class="sm-card-header">
<span class="material-icons">badge</span>
<h3>${_('server_mgmt.host_info')}</h3>
</div>
<div class="sm-info-grid" id="sm-host-info"></div>
</div>
</div>
</section>
<!-- Terminal tab -->
<section class="sm-tab-panel" id="sm-panel-terminal" role="tabpanel" hidden>
<div class="sm-terminal-toolbar">
<button class="btn btn-primary" id="sm-term-connect">
<span class="material-icons">play_arrow</span>
${_('server_mgmt.term_connect')}
</button>
<button class="btn btn-secondary" id="sm-term-disconnect" disabled>
<span class="material-icons">stop</span>
${_('server_mgmt.term_disconnect')}
</button>
<button class="btn btn-tertiary" id="sm-term-clear" disabled>
<span class="material-icons">delete_sweep</span>
${_('server_mgmt.term_clear')}
</button>
<span class="sm-term-status" id="sm-term-status">${_('server_mgmt.term_disconnected')}</span>
</div>
<div class="sm-terminal-warning">
<span class="material-icons">warning</span>
<span>${_('server_mgmt.term_warning')}</span>
</div>
<div class="sm-terminal-host" id="sm-terminal-host"></div>
<p class="sm-term-hint">${_('server_mgmt.term_hint')}</p>
</section>
<!-- Files tab -->
<section class="sm-tab-panel" id="sm-panel-files" role="tabpanel" hidden>
<div class="sm-files-toolbar">
<button class="btn btn-tertiary" id="sm-files-up" title="${_('server_mgmt.files_up')}">
<span class="material-icons">arrow_upward</span>
</button>
<button class="btn btn-tertiary" id="sm-files-refresh" title="${_('common.refresh')}">
<span class="material-icons">refresh</span>
</button>
<input type="text" class="form-input sm-files-path" id="sm-files-path" value="/" spellcheck="false">
<button class="btn btn-secondary" id="sm-files-go">${_('server_mgmt.files_go')}</button>
<span class="spacer"></span>
<button class="btn btn-tertiary" id="sm-files-mkdir">
<span class="material-icons">create_new_folder</span>
${_('server_mgmt.files_mkdir')}
</button>
</div>
<div class="sm-files-table-wrapper">
<table class="data-table sm-files-table">
<thead>
<tr>
<th style="width:40px"></th>
<th>${_('server_mgmt.files_name')}</th>
<th style="width:110px">${_('server_mgmt.files_size')}</th>
<th style="width:90px">${_('server_mgmt.files_perms')}</th>
<th style="width:160px">${_('server_mgmt.files_mtime')}</th>
<th style="width:160px">${_('common.actions')}</th>
</tr>
</thead>
<tbody id="sm-files-body">
<tr><td colspan="6"><div class="empty-state"><span class="material-icons">folder_off</span><p>${_('common.loading')}…</p></div></td></tr>
</tbody>
</table>
</div>
<!-- Inline file editor -->
<div class="sm-file-editor" id="sm-file-editor" hidden>
<div class="sm-file-editor-header">
<span class="material-icons">edit_document</span>
<span class="sm-file-editor-path" id="sm-file-editor-path"></span>
<span class="spacer"></span>
<button class="btn btn-primary" id="sm-file-save">
<span class="material-icons">save</span>${_('common.save')}
</button>
<button class="btn btn-tertiary" id="sm-file-close">
<span class="material-icons">close</span>${_('common.cancel')}
</button>
</div>
<textarea class="sm-file-textarea" id="sm-file-textarea" spellcheck="false"></textarea>
<p class="sm-file-meta" id="sm-file-meta"></p>
</div>
</section>
<!-- Services tab -->
<section class="sm-tab-panel" id="sm-panel-services" role="tabpanel" hidden>
<div class="sm-services-toolbar">
<input type="search" class="form-input sm-services-search" id="sm-services-search" placeholder="${_('server_mgmt.svc_search_placeholder')}">
<button class="btn btn-tertiary" id="sm-services-refresh">
<span class="material-icons">refresh</span>${_('common.refresh')}
</button>
<span class="sm-services-count" id="sm-services-count"></span>
</div>
<div class="sm-services-table-wrapper">
<table class="data-table sm-services-table">
<thead>
<tr>
<th>${_('server_mgmt.svc_name')}</th>
<th style="width:120px">${_('server_mgmt.svc_state')}</th>
<th>${_('server_mgmt.svc_description')}</th>
<th style="width:280px">${_('common.actions')}</th>
</tr>
</thead>
<tbody id="sm-services-body">
<tr><td colspan="4"><div class="empty-state"><span class="material-icons">miscellaneous_services</span><p>${_('common.loading')}…</p></div></td></tr>
</tbody>
</table>
</div>
</section>
</div>
</div>
</div>
`
}) %>