mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-03 08:00:32 +00:00
Remove System Information window
This commit is contained in:
@@ -1,295 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import UIWindow from './UIWindow.js';
|
||||
import * as utils from '../../../puter-js/src/lib/utils.js';
|
||||
|
||||
const triggerRefreshBtnAnimation = ($btn) => {
|
||||
const $icon = $btn.find('.update-usage-details-icon');
|
||||
|
||||
const icon = $icon[0];
|
||||
const clone = icon.cloneNode(true);
|
||||
// Cloned node required to get animation to play on refresh
|
||||
icon.parentNode.replaceChild(clone, icon);
|
||||
};
|
||||
|
||||
// Leverage User-Agent Client Hints API to request user browser information
|
||||
async function getClientInfo () {
|
||||
let clientInfo = [];
|
||||
|
||||
// Get browser & OS info
|
||||
if ( navigator.userAgentData ) {
|
||||
const uaData = await navigator.userAgentData.getHighEntropyValues([
|
||||
'platform', 'platformVersion', 'model', 'fullVersionList',
|
||||
]);
|
||||
|
||||
const browser = uaData.brands?.[0]?.brand || 'Unknown';
|
||||
const browserVersion = uaData.brands?.[0]?.version || 'Unknown';
|
||||
const os = uaData.platform || 'Unknown';
|
||||
const osVersion = uaData.platformVersion || 'Unknown';
|
||||
|
||||
clientInfo.push ({
|
||||
key: 'browser',
|
||||
icon: 'system-info-browser.svg',
|
||||
i18n_key: 'browser',
|
||||
title: i18n('browser'),
|
||||
value: `${browser} ${browserVersion}`,
|
||||
},
|
||||
{
|
||||
key: 'os',
|
||||
icon: 'system-info-os.svg',
|
||||
i18n_key: 'system-info-os',
|
||||
title: i18n('os'),
|
||||
value: `${os} ${osVersion}`,
|
||||
});
|
||||
} else {
|
||||
// Fallback for older browsers
|
||||
const userAgent = navigator.userAgent;
|
||||
let os = 'Unknown';
|
||||
if ( /Win/.test(userAgent) ) os = 'Windows';
|
||||
else if ( /Mac/.test(userAgent) ) os = 'macOS';
|
||||
else if ( /Linux/.test(userAgent) ) os = 'Linux';
|
||||
else if ( /Android/.test(userAgent) ) os = 'Android';
|
||||
else if ( /iPhone|iPad|iPod/.test(userAgent) ) os = 'iOS';
|
||||
|
||||
clientInfo.push({
|
||||
key: 'os',
|
||||
icon: 'system-info-os.svg',
|
||||
i18n_key: 'os',
|
||||
title: i18n('os'),
|
||||
value: os,
|
||||
});
|
||||
}
|
||||
|
||||
// Get hardware info
|
||||
const cpuCores = navigator.hardwareConcurrency || 'Unknown';
|
||||
const ram = navigator.deviceMemory ? `${navigator.deviceMemory} GB (approx)` : 'Unknown';
|
||||
|
||||
clientInfo.push({
|
||||
key: 'cpu_cores',
|
||||
icon: 'system-info-cpu.svg',
|
||||
i18n_key: 'cpu_cores',
|
||||
title: i18n('cpu_cores'),
|
||||
value: `${cpuCores} cores`,
|
||||
},
|
||||
{
|
||||
key: 'ram',
|
||||
icon: 'system-info-ram.svg',
|
||||
i18n_key: 'ram',
|
||||
title: i18n('ram'),
|
||||
value: ram,
|
||||
});
|
||||
|
||||
// Get screen info
|
||||
const screenResolution = `${window.screen.width}x${window.screen.height}`;
|
||||
const pixelRatio = window.devicePixelRatio;
|
||||
const colorDepth = window.screen.colorDepth;
|
||||
|
||||
clientInfo.push({
|
||||
key: 'screen_resolution',
|
||||
icon: 'system-info-screen.svg',
|
||||
i18n_key: 'screen_resolution',
|
||||
title: i18n('screen_resolution'),
|
||||
value: screenResolution,
|
||||
},
|
||||
{
|
||||
key: 'pixel_ratio',
|
||||
icon: 'system-info-pixel.svg',
|
||||
i18n_key: 'pixel_ratio',
|
||||
title: i18n('pixel_ratio'),
|
||||
value: `${pixelRatio}x`,
|
||||
},
|
||||
{
|
||||
key: 'color_depth',
|
||||
icon: 'system-info-color.svg',
|
||||
i18n_key: 'color_depth',
|
||||
title: i18n('color_depth'),
|
||||
value: `${colorDepth} bits`,
|
||||
});
|
||||
|
||||
return clientInfo;
|
||||
}
|
||||
|
||||
async function getServerInfo (options = {}) {
|
||||
const APIOrigin = window.puter?.APIOrigin;
|
||||
const authToken = window.puter?.authToken;
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = utils.initXhr('/serverInfo', APIOrigin, authToken, 'get');
|
||||
utils.setupXhrEventHandlers(xhr, options.success, options.error, resolve, reject);
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
async function getServerInfoFormatted () {
|
||||
try {
|
||||
const rawServerData = await getServerInfo();
|
||||
|
||||
// Map raw data to render-ready array
|
||||
return [
|
||||
{
|
||||
key: 'os',
|
||||
icon: 'system-info-os.svg',
|
||||
i18n_key: 'os',
|
||||
title: i18n('os'),
|
||||
value: rawServerData.os?.pretty || `${rawServerData.os?.type || 'Unknown'} ${rawServerData.os?.release || ''}`,
|
||||
},
|
||||
{
|
||||
key: 'cpu',
|
||||
icon: 'system-info-cpu.svg',
|
||||
i18n_key: 'cpu',
|
||||
title: i18n('cpu'),
|
||||
value: `${rawServerData.cpu?.model || 'Unknown'} (${rawServerData.cpu?.cores || 0} cores)`,
|
||||
},
|
||||
{
|
||||
key: 'ram',
|
||||
icon: 'system-info-ram.svg',
|
||||
i18n_key: 'ram',
|
||||
title: i18n('ram'),
|
||||
value: `${rawServerData.ram?.freeGB || 0} Free / ${rawServerData.ram?.totalGB || 0} GB`,
|
||||
},
|
||||
{
|
||||
key: 'disk_storage',
|
||||
icon: 'system-info-storage.svg',
|
||||
i18n_key: 'disk_storage',
|
||||
title: i18n('disk_storage'),
|
||||
value: `${rawServerData.disk?.used || 0} Used / ${rawServerData.disk?.total || 0} GB`,
|
||||
},
|
||||
{
|
||||
key: 'uptime',
|
||||
icon: 'system-info-time.svg',
|
||||
i18n_key: 'uptime',
|
||||
title: i18n('uptime'),
|
||||
value: rawServerData.uptime?.pretty || 'N/A',
|
||||
},
|
||||
];
|
||||
} catch ( err ) {
|
||||
console.error('Failed to fetch server info:', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function renderSystemInfo ( information ) {
|
||||
let html = '';
|
||||
for ( const info of information ) {
|
||||
html += `<div class="systeminfo-item">
|
||||
<h3 class='systeminfo-title'>${info.title}</h3>
|
||||
<div class='systeminfo-value'>
|
||||
<img src='${window.icons[info.icon]}' class="systeminfo-icon" alt='${info.i18n} image'>
|
||||
${info.value}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
async function UIWindowSystemInfo (options) {
|
||||
return new Promise(async (resolve) => {
|
||||
// Build client & Server containers & headers
|
||||
const h = `<div class="systeminfo-container">
|
||||
<div class="clientinfo-container">
|
||||
<h1>${i18n('client_information')}
|
||||
<button class="update-usage-details client-btn" style="float:right;">
|
||||
<svg class="update-usage-details-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2z"/>
|
||||
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466"/>
|
||||
</svg>
|
||||
</button>
|
||||
</h1>
|
||||
<div class="clientinfo-content"></div>
|
||||
</div>
|
||||
<div class="serverinfo-container">
|
||||
<h1>${i18n('server_information')}
|
||||
<button class="update-usage-details server-btn" style="float:right;">
|
||||
<svg class="update-usage-details-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2z"/>
|
||||
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466"/>
|
||||
</svg>
|
||||
</button>
|
||||
</h1>
|
||||
<div class="serverinfo-content"></div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: 'System Information',
|
||||
app: 'System Information',
|
||||
single_instance: true,
|
||||
icon: null,
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: true,
|
||||
selectable_body: false,
|
||||
allow_context_menu: false,
|
||||
is_resizable: true,
|
||||
is_droppable: false,
|
||||
init_center: true,
|
||||
allow_native_ctxmenu: true,
|
||||
allow_user_select: true,
|
||||
backdrop: false,
|
||||
width: 560,
|
||||
height: 540,
|
||||
dominant: true,
|
||||
show_in_taskbar: true,
|
||||
draggable_body: false,
|
||||
body_css: {
|
||||
width: 'initial',
|
||||
height: 'calc(100% - 30px)',
|
||||
overflow: 'auto',
|
||||
},
|
||||
...options?.window_options ?? {},
|
||||
});
|
||||
|
||||
// Scope jQuery to this window
|
||||
const $win = $(el_window);
|
||||
|
||||
// Inject client info on launch
|
||||
const clientInfo = await getClientInfo();
|
||||
const clientInfohtml = renderSystemInfo(clientInfo);
|
||||
$win.find('.clientinfo-content').html(clientInfohtml);
|
||||
// Inject server info on launch
|
||||
$win.find('.serverinfo-content').html('<p style="font-weight:500;font-size:14px;color:#3C4963">Loading server info...</p>');
|
||||
const serverInfo = await getServerInfoFormatted();
|
||||
const serverInfohtml = renderSystemInfo(serverInfo);
|
||||
$win.find('.serverinfo-content').html(serverInfohtml);
|
||||
|
||||
// Spin both reset buttons once on launch
|
||||
const $icons = $win.find('.update-usage-details-icon');
|
||||
$icons.addClass('spin-once');
|
||||
|
||||
// Refresh button onclick event
|
||||
$win.on('click', '.update-usage-details', async function () {
|
||||
if ( $(this).hasClass('client-btn') ) {
|
||||
triggerRefreshBtnAnimation($(this));
|
||||
const clientInfo = await getClientInfo();
|
||||
const clientInfohtml = renderSystemInfo(clientInfo);
|
||||
$win.find('.clientinfo-content').html(clientInfohtml);
|
||||
} else {
|
||||
triggerRefreshBtnAnimation($(this));
|
||||
const serverInfo = await getServerInfoFormatted();
|
||||
const serverInfohtml = renderSystemInfo(serverInfo);
|
||||
$win.find('.serverinfo-content').html(serverInfohtml);
|
||||
}
|
||||
});
|
||||
|
||||
resolve(el_window);
|
||||
});
|
||||
}
|
||||
|
||||
export default UIWindowSystemInfo;
|
||||
@@ -17,29 +17,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import UIWindowSystemInfo from '../UI/UIWindowSystemInfo.js';
|
||||
|
||||
console.debug('[puter] modify-user-options-menu loaded');
|
||||
|
||||
$(window).on('ctxmenu-will-open', (event) => {
|
||||
if ( event.detail.options?.id === 'user-options-menu' ) {
|
||||
// Define array of new menu items
|
||||
const newMenuItems = [
|
||||
// System Information window
|
||||
{
|
||||
id: 'system_information',
|
||||
html: 'System Information',
|
||||
html_active: 'System Information',
|
||||
action: async function () {
|
||||
try {
|
||||
console.debug('[puter] System Information click');
|
||||
await UIWindowSystemInfo();
|
||||
console.debug('[puter] System Information opened');
|
||||
} catch (e) {
|
||||
console.error('[puter] System Information failed', e);
|
||||
}
|
||||
},
|
||||
},
|
||||
// Separator
|
||||
'-',
|
||||
// 'Developer', opens developer site in new tab
|
||||
|
||||
Reference in New Issue
Block a user