mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 01:38:19 +08:00
服务状态(/status)
This commit is contained in:
1 parent
b2989cb9ea
commit
216a4a91e4
19 files changed
+322
-136
No files matched your search
@@ -18,6 +18,7 @@ module.exports = {
|
||||
"no-plusplus": "off",
|
||||
"no-console": "off",
|
||||
"no-extend-native": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"no-restricted-syntax": "off",
|
||||
"max-classes-per-file": "off",
|
||||
"radix": "off",
|
||||
|
||||
+15
-13
@@ -21,6 +21,8 @@ const {
|
||||
PERM_LOGGEDIN,
|
||||
} = require('../permission');
|
||||
|
||||
const { geoip, useragent } = global.Hydro.lib;
|
||||
|
||||
class HomeHandler extends Handler {
|
||||
async contest(domainId) {
|
||||
if (this.user.hasPerm(PERM_VIEW_CONTEST)) {
|
||||
@@ -81,13 +83,13 @@ class HomeSecurityHandler extends Handler {
|
||||
// TODO(iceboy): pagination? or limit session count for uid?
|
||||
// TODO(masnn): UA & IP
|
||||
const sessions = await token.getSessionListByUid(this.user._id);
|
||||
const parsed = sessions.map((session) => ({
|
||||
...session,
|
||||
// updateUa: useragent.parse(session.updateUa || session.createUa || ''),
|
||||
// updateGeoip: geoip.ip2geo(session.updateIp || session.createIp, this.user.viewLang),
|
||||
_id: md5(session._id),
|
||||
isCurrent: session._id === this.session._id,
|
||||
}));
|
||||
const parsed = [];
|
||||
for (const session of sessions) {
|
||||
session.isCurrent = session._id === this.session._id;
|
||||
session._id = md5(session._id);
|
||||
if (useragent) session.updateUa = useragent.parse(session.updateUa || session.createUa || '');
|
||||
if (geoip) session.updateGeoip = geoip.lookup(session.updateIp || session.createIp);
|
||||
}
|
||||
this.response.template = 'home_security.html';
|
||||
this.response.body = { sessions: parsed };
|
||||
}
|
||||
@@ -153,7 +155,7 @@ class HomeSettingsHandler extends Handler {
|
||||
|
||||
async post(args) {
|
||||
// FIXME validation
|
||||
await user.setById(domainId, this.user._id, args);
|
||||
await user.setById(args.domainId, this.user._id, args);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
@@ -166,9 +168,10 @@ class UserChangemailWithCodeHandler extends Handler {
|
||||
}
|
||||
const udoc = await user.getByEmail(tdoc.mail);
|
||||
if (udoc) throw new UserAlreadyExistError(tdoc.mail);
|
||||
// TODO(twd2): Ensure mail is unique.
|
||||
await user.setEmail(this.user._id, tdoc.mail);
|
||||
await token.delete(code, token.TYPE_CHANGEMAIL);
|
||||
await Promise.all([
|
||||
user.setEmail(this.user._id, tdoc.mail),
|
||||
token.delete(code, token.TYPE_CHANGEMAIL),
|
||||
]);
|
||||
this.response.redirect = '/home/security';
|
||||
}
|
||||
}
|
||||
@@ -211,8 +214,7 @@ class HomeMessagesHandler extends Handler {
|
||||
if (type === 'single') {
|
||||
mdoc = mdoc.reply[mdoc.reply.length - 1];
|
||||
}
|
||||
// TODO(twd2): improve here:
|
||||
// projection
|
||||
// TODO(twd2): improve here: projection
|
||||
mdoc.from_udoc = this.user;
|
||||
mdoc.to_udoc = udoc;
|
||||
this.udoc(mdoc, 'from');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const user = require('../model/user');
|
||||
const domain = require('../model/domain');
|
||||
const setting = require('../model/setting');
|
||||
const system = require('../model/system');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const { PERM_MANAGE } = require('../permission');
|
||||
const hpm = require('../lib/hpm');
|
||||
@@ -53,6 +54,7 @@ class ManageEditHandler extends ManageHandler {
|
||||
|
||||
class ManageUserHandler extends ManageHandler {
|
||||
async get({ domainId }) {
|
||||
// FIXME(masnn) UPDATE CODE
|
||||
const uids = [];
|
||||
const rudocs = {};
|
||||
const [udocs, roles] = await Promise.all([
|
||||
@@ -73,7 +75,7 @@ class ManageUserHandler extends ManageHandler {
|
||||
];
|
||||
this.response.template = 'manage_user.html';
|
||||
this.response.body = {
|
||||
roles, rolesSelect, rudocs, udict, system: sys, path,
|
||||
roles, rolesSelect, rudocs, udict, path,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
const { PERM_JUDGE } = require('../permission');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const db = require('../service/db');
|
||||
|
||||
const coll = db.collection('status');
|
||||
|
||||
class StatusHandler extends Handler {
|
||||
async get() {
|
||||
const stats = await coll.find().sort({ type: 1, updateAt: -1 }).toArray();
|
||||
for (const i in stats) {
|
||||
let desc = '';
|
||||
const online = new Date(stats[i].updateAt).getTime() > new Date().getTime() - 300000;
|
||||
if (!online) desc = 'Offline';
|
||||
desc = desc || 'Online';
|
||||
stats[i].status = desc;
|
||||
}
|
||||
this.response.body = { stats };
|
||||
this.response.template = 'status.html';
|
||||
}
|
||||
}
|
||||
|
||||
class StatusUpdateHandler extends Handler {
|
||||
async post(args) {
|
||||
this.checkPerm(PERM_JUDGE);
|
||||
await coll.updateOne({ _id: args._id }, { $set: args }, { upsert: true });
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
Route('/status', StatusHandler);
|
||||
Route('/status/update', StatusUpdateHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.status = module.exports = { StatusHandler, StatusUpdateHandler, apply };
|
||||
@@ -0,0 +1,91 @@
|
||||
const domain = require('../model/domain');
|
||||
const system = require('../model/system');
|
||||
const setting = require('../model/setting');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const { PERM_MANAGE } = require('../permission');
|
||||
const hpm = require('../lib/hpm');
|
||||
const loader = require('../loader');
|
||||
|
||||
class SystemHandler extends Handler {
|
||||
async prepare({ domainId }) {
|
||||
this.checkPerm(PERM_MANAGE);
|
||||
this.domain = await domain.get(domainId);
|
||||
}
|
||||
}
|
||||
|
||||
class SystemDashboardHandler extends SystemHandler {
|
||||
async get() {
|
||||
const path = [
|
||||
['Hydro', '/'],
|
||||
['manage', '/manage'],
|
||||
['manage_dashboard', null],
|
||||
];
|
||||
this.response.template = 'manage_dashboard.html';
|
||||
this.response.body = { domain: this.domain, path };
|
||||
}
|
||||
}
|
||||
|
||||
class SystemModuleHandler extends SystemHandler {
|
||||
async get() {
|
||||
const installed = await hpm.getInstalled();
|
||||
const path = [
|
||||
['Hydro', '/'],
|
||||
['manage', '/manage'],
|
||||
['manage_module', null],
|
||||
];
|
||||
this.response.body = { installed, active: loader.active, path };
|
||||
this.response.template = 'manage_module.html';
|
||||
}
|
||||
|
||||
async postInstall({ url, id }) {
|
||||
await hpm.install(url, id);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postDelete({ id }) {
|
||||
await hpm.del(id);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
class SystemSettingHandler extends SystemHandler {
|
||||
async get() {
|
||||
this.response.template = 'manage_settings.html';
|
||||
const current = {};
|
||||
const settings = setting.SYSTEM_SETTINGS;
|
||||
for (const s of settings) {
|
||||
current[s.key] = await system.get(s.key);
|
||||
}
|
||||
this.response.body = {
|
||||
current, settings,
|
||||
};
|
||||
}
|
||||
|
||||
async post(args) {
|
||||
const tasks = [];
|
||||
for (const key in args) {
|
||||
if (typeof args[key] === 'object') {
|
||||
const subtasks = [];
|
||||
for (const sub in args[key]) {
|
||||
subtasks.push(system.set(`${key}.${sub}`, args[key][sub]));
|
||||
}
|
||||
tasks.push(Promise.all(subtasks));
|
||||
} else tasks.push(system.set(key, args[key]));
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
Route('/system', module.exports.SystemDashboardHandler);
|
||||
Route('/system/module', module.exports.SystemModuleHandler);
|
||||
Route('/system/setting', module.exports.SystemSettingHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.manage = module.exports = {
|
||||
SystemDashboardHandler,
|
||||
SystemModuleHandler,
|
||||
SystemSettingHandler,
|
||||
apply,
|
||||
};
|
||||
+1
-1
@@ -43,7 +43,7 @@ function size(s, base = 1) {
|
||||
const unit = 1024;
|
||||
const unitNames = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
||||
for (const unitName of unitNames) {
|
||||
if (s < unit) return '{0} {1}'.format(Math.round(s), unitName);
|
||||
if (s < unit) return '{0} {1}'.format(Math.round(s * 10) / 10, unitName);
|
||||
s /= unit;
|
||||
}
|
||||
return '{0} {1}'.format(Math.round(s * unit), unitNames[unitNames.length - 1]);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
const systeminformation = require('systeminformation');
|
||||
const { size } = require('./misc');
|
||||
|
||||
const cache = {};
|
||||
|
||||
async function get() {
|
||||
const [Cpu, Memory, OsInfo, CurrentLoad, CpuFlags, CpuTemp, Battery] = await Promise.all([
|
||||
systeminformation.cpu(),
|
||||
systeminformation.mem(),
|
||||
systeminformation.osInfo(),
|
||||
systeminformation.currentLoad(),
|
||||
systeminformation.cpuFlags(),
|
||||
systeminformation.cpuTemperature(),
|
||||
systeminformation.battery(),
|
||||
]);
|
||||
const cpu = `${Cpu.manufacturer} ${Cpu.brand}`;
|
||||
const memory = `${size(Memory.active)}/${size(Memory.total)}`;
|
||||
const osinfo = `${OsInfo.distro} ${OsInfo.release} ${OsInfo.codename} ${OsInfo.kernel} ${OsInfo.arch}`;
|
||||
const load = `${CurrentLoad.avgload}`;
|
||||
const flags = CpuFlags;
|
||||
let battery;
|
||||
if (!Battery.hasbattery) battery = 'No battery';
|
||||
else battery = `${Battery.type} ${Battery.model} ${Battery.percent}%${Battery.ischarging ? ' Charging' : ''}`;
|
||||
const _id = OsInfo.serial;
|
||||
cache.cpu = cpu;
|
||||
cache.osinfo = osinfo;
|
||||
cache.flags = flags;
|
||||
cache._id = _id;
|
||||
return {
|
||||
_id, cpu, memory, osinfo, load, flags, CpuTemp, battery,
|
||||
};
|
||||
}
|
||||
|
||||
async function update() {
|
||||
const [Memory, CurrentLoad, CpuTemp, Battery] = await Promise.all([
|
||||
systeminformation.mem(),
|
||||
systeminformation.currentLoad(),
|
||||
systeminformation.cpuTemperature(),
|
||||
systeminformation.battery(),
|
||||
]);
|
||||
const {
|
||||
_id, cpu, osinfo, flags,
|
||||
} = cache;
|
||||
const memory = `${size(Memory.active)}/${size(Memory.total)}`;
|
||||
const load = `${CurrentLoad.avgload}`;
|
||||
let battery;
|
||||
if (!Battery.hasbattery) battery = 'No battery';
|
||||
else battery = `${Battery.type} ${Battery.model} ${Battery.percent}%${Battery.ischarging ? ' Charging' : ''}`;
|
||||
return [
|
||||
_id,
|
||||
{
|
||||
memory, load, battery, CpuTemp,
|
||||
},
|
||||
{
|
||||
_id, cpu, memory, osinfo, load, flags, battery, CpuTemp,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
global.Hydro.lib.sysinfo = module.exports = { get, update };
|
||||
+3
-2
@@ -229,11 +229,12 @@ async function load() {
|
||||
const builtinLib = [
|
||||
'axios', 'download', 'i18n', 'mail', 'markdown',
|
||||
'md5', 'misc', 'paginate', 'hash.hydro', 'rank',
|
||||
'template', 'validator', 'nav',
|
||||
'template', 'validator', 'nav', 'sysinfo',
|
||||
];
|
||||
for (const i of builtinLib) require(`./lib/${i}`);
|
||||
await lib();
|
||||
require('./service/gridfs');
|
||||
require('./service/monitor');
|
||||
const server = require('./service/server');
|
||||
await server.prepare();
|
||||
await service();
|
||||
@@ -256,7 +257,7 @@ async function load() {
|
||||
const builtinHandler = [
|
||||
'home', 'problem', 'record', 'judge', 'user',
|
||||
'contest', 'training', 'discussion', 'manage', 'import',
|
||||
'fs',
|
||||
'fs', 'status',
|
||||
];
|
||||
for (const i of builtinHandler) require(`./handler/${i}`);
|
||||
await model();
|
||||
|
||||
@@ -23,6 +23,7 @@ async function add(
|
||||
) {
|
||||
const _id = new ObjectID();
|
||||
const doc = {
|
||||
_id,
|
||||
content,
|
||||
owner,
|
||||
domainId,
|
||||
@@ -53,8 +54,10 @@ async function set(domainId, docType, docId, args) {
|
||||
}
|
||||
|
||||
function deleteOne(domainId, docType, docId) {
|
||||
// TODO(twd2): delete status?
|
||||
return coll.deleteOne({ domainId, docType, docId });
|
||||
return Promise.all([
|
||||
coll.deleteMany({ domainId, docType, docId }),
|
||||
coll.deleteOne({ domainId, docType, docId }),
|
||||
]);
|
||||
}
|
||||
|
||||
function deleteMulti(domainId, docType, args = {}) {
|
||||
@@ -134,9 +137,7 @@ async function getSub(domainId, docType, docId, key, subId) {
|
||||
});
|
||||
if (!doc) return [null, null];
|
||||
for (const sdoc of doc[key] || []) {
|
||||
if (sdoc._id === subId) {
|
||||
return [doc, sdoc];
|
||||
}
|
||||
if (sdoc._id === subId) return [doc, sdoc];
|
||||
}
|
||||
return [doc, null];
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,3 +1,4 @@
|
||||
const builtin = require('./builtin');
|
||||
const document = require('./document');
|
||||
const system = require('./system');
|
||||
const { UserNotFoundError, UserAlreadyExistError } = require('../error');
|
||||
@@ -40,15 +41,15 @@ class USER {
|
||||
async function getPerm(domainId, udoc) {
|
||||
if (udoc._id === 1) { // Is Guest
|
||||
const p = await document.get(domainId, document.TYPE_DOMAIN_ROLE, 'guest');
|
||||
return p.content;
|
||||
return p ? p.content : builtin.BUILTIN_ROLES.guest.perm;
|
||||
}
|
||||
if (udoc.priv === 1) {
|
||||
if (udoc.priv === 1) { // Is superadmin
|
||||
const p = await document.get(domainId, document.TYPE_DOMAIN_ROLE, 'admin');
|
||||
return p.content;
|
||||
return p ? p.content : builtin.BUILTIN_ROLES.admin.perm;
|
||||
}
|
||||
const role = await document.getStatus(domainId, document.TYPE_DOMAIN_ROLE, 0, udoc._id);
|
||||
const p = await document.get(domainId, document.TYPE_DOMAIN_ROLE, role.role || 'default');
|
||||
return p.content;
|
||||
const p = await document.get(domainId, document.TYPE_DOMAIN_ROLE, (role || {}).role || 'default');
|
||||
return p ? p.content : builtin.BUILTIN_ROLES.default.perm;
|
||||
}
|
||||
|
||||
async function getById(domainId, _id) {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
const db = require('./db');
|
||||
const sysinfo = require('../lib/sysinfo');
|
||||
|
||||
const coll = db.collection('status');
|
||||
|
||||
async function update() {
|
||||
const [_id, $set] = await sysinfo.update();
|
||||
await coll.updateOne(
|
||||
{ _id },
|
||||
{ $set: { ...$set, updateAt: new Date() } },
|
||||
{ upsert: true },
|
||||
);
|
||||
}
|
||||
|
||||
async function postInit() {
|
||||
const info = await sysinfo.get();
|
||||
await coll.updateOne(
|
||||
{ _id: info._id },
|
||||
{ $set: { ...info, updateAt: new Date() } },
|
||||
{ upsert: true },
|
||||
);
|
||||
setInterval(update, 3 * 60 * 1000);
|
||||
}
|
||||
|
||||
global.Hydro.service.monitor = module.exports = { postInit };
|
||||
@@ -1,95 +0,0 @@
|
||||
module.exports = {
|
||||
TEXT: 'Assignment',
|
||||
check() {},
|
||||
stat(tdoc, journal) {
|
||||
const effective = {};
|
||||
const detail = [];
|
||||
let score = 0;
|
||||
let time = 0;
|
||||
for (const j in journal) {
|
||||
if (tdoc.pids.includes(j.pid)
|
||||
&& !(effective.includes(j.pid) && effective[j.pid].accept)) {
|
||||
effective[j.pid] = j;
|
||||
}
|
||||
}
|
||||
const _time = (jdoc) => jdoc.rid.generationTime - Math.floor(tdoc.beginAt / 1000);
|
||||
for (const j in effective) {
|
||||
detail.push({
|
||||
...effective[j],
|
||||
time: _time(effective[j]),
|
||||
});
|
||||
}
|
||||
for (const d of detail) {
|
||||
score += d.score;
|
||||
time += d.time;
|
||||
}
|
||||
return {
|
||||
score, time, detail,
|
||||
};
|
||||
},
|
||||
scoreboard(isExport, _, tdoc, rankedTsdocs, udict, pdict) {
|
||||
const columns = [
|
||||
{ type: 'rank', value: _('Rank') },
|
||||
{ type: 'user', value: _('User') },
|
||||
{ type: 'display_name', value: _('Display Name') },
|
||||
{ type: 'total_score', value: _('Score') },
|
||||
];
|
||||
if (isExport) {
|
||||
columns.push(
|
||||
{ type: 'total_original_score', value: _('Original Score') },
|
||||
{ type: 'total_time', value: _('Total Time (Seconds)') },
|
||||
);
|
||||
}
|
||||
columns.push({ type: 'total_time_str', value: _('Total Time') });
|
||||
for (const i in tdoc.pids) {
|
||||
if (isExport) {
|
||||
columns.push(
|
||||
{ type: 'problem_score', value: '#{0} {1}'.format(i + 1, pdict[tdoc.pids[i]].title) },
|
||||
{ type: 'problem_original_score', value: '#{0} {1}'.format(i + 1, _('Original Score')) },
|
||||
{ type: 'problem_time', value: '#{0} {1}'.format(i + 1, _('Time (Seconds)')) },
|
||||
{ type: 'problem_time_str', value: '#{0} {1}'.format(i + 1, _('Time')) },
|
||||
);
|
||||
} else columns.push({ type: 'problem_detail', value: '#{0}'.format(i + 1), raw: pdict[tdoc.pids[i]] });
|
||||
}
|
||||
const rows = [columns];
|
||||
for (const [rank, tsdoc] in rankedTsdocs) {
|
||||
const tsddict = {};
|
||||
if (tsdoc.detail) { for (const item of tsdoc.detail) tsddict[item.pid] = item; }
|
||||
const row = [
|
||||
{ type: 'string', value: rank },
|
||||
{ type: 'user', value: udict[tsdoc.uid].uname, raw: udict[tsdoc.uid] },
|
||||
{ type: 'string', value: tsdoc.penalty_score || 0 },
|
||||
];
|
||||
if (isExport) {
|
||||
row.push(
|
||||
{ type: 'string', value: tsdoc.score || 0 },
|
||||
{ type: 'string', value: tsdoc.time || 0.0 },
|
||||
);
|
||||
}
|
||||
row.push({ type: 'string', value: tsdoc.time || 0 });
|
||||
for (const pid of tdoc.pids) {
|
||||
const rdoc = (tsddict[pid] || {}).rid || null;
|
||||
const colScore = (tsddict[pid] || {}).penalty_score || '-';
|
||||
const colOriginalScore = (tsddict[pid] || {}).score || '-';
|
||||
const colTime = (tsddict[pid] || {}).time || '-';
|
||||
const colTimeStr = colTime !== '-' ? colTime : '-';
|
||||
if (isExport) {
|
||||
row.push(
|
||||
{ type: 'string', value: colScore },
|
||||
{ type: 'string', value: colOriginalScore },
|
||||
{ type: 'string', value: colTime },
|
||||
{ type: 'string', value: colTimeStr },
|
||||
);
|
||||
} else {
|
||||
row.push({
|
||||
type: 'record',
|
||||
value: '{0} / {1}\n{2}'.format(colScore, colOriginalScore, colTimeStr),
|
||||
raw: rdoc,
|
||||
});
|
||||
}
|
||||
}
|
||||
rows.push(row);
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"id": "contest-rule-homework",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
const homework = require('./homework');
|
||||
|
||||
global.Hydro.model.contest.RULES.homework = homework;
|
||||
@@ -56,6 +56,7 @@ const tasks = {
|
||||
reply: 'reply',
|
||||
parent_doc_id: 'parentId',
|
||||
parent_doc_type: 'parentType',
|
||||
num_replies: 'nReply',
|
||||
views: 'views',
|
||||
highlight: 'highlight',
|
||||
ip: 'ip',
|
||||
@@ -244,8 +245,21 @@ async function task(name, src, report) {
|
||||
for (let i = 0; i <= total; i++) {
|
||||
const docs = await cursor[name](src).skip(i * 50).limit(50).toArray();
|
||||
const res = [];
|
||||
for (const doc of docs) res.push(tasks[name](doc));
|
||||
if (res.length) await dst.collection(name).insertMany(await Promise.all(res));
|
||||
for (const doc of docs) {
|
||||
const d = await tasks[name](doc);
|
||||
if (d) {
|
||||
if (d.docId && d.docType) {
|
||||
res.push(dst.collection(name).updateOne({
|
||||
docId: d.docId, docType: d.docType,
|
||||
}, { $set: d }, { upsert: true }));
|
||||
} else if (d._id) {
|
||||
res.push(dst.collection(name).updateOne({
|
||||
_id: d._id,
|
||||
}, { $set: d }, { upsert: true }));
|
||||
} else res.push(dst.collection(name).insertOne(d));
|
||||
}
|
||||
}
|
||||
await Promise.all(res);
|
||||
await report({ progress: Math.round(100 * ((i + 1) / (total + 1))) });
|
||||
}
|
||||
await fixPid(report);
|
||||
|
||||
+4
-5
@@ -21,7 +21,8 @@
|
||||
"nodemailer": "^6.3.1",
|
||||
"nunjucks": "^3.2.1",
|
||||
"prismjs": "^1.20.0",
|
||||
"sockjs": "^0.3.20"
|
||||
"sockjs": "^0.3.20",
|
||||
"systeminformation": "^4.26.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^6.8.0",
|
||||
@@ -39,12 +40,10 @@
|
||||
},
|
||||
"pkg": {
|
||||
"scripts": [
|
||||
"hydro/**.js"
|
||||
".build/development.js"
|
||||
],
|
||||
"assets": [
|
||||
".uibuild/*",
|
||||
"locales/*",
|
||||
"templates/*"
|
||||
".build/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{% set page_name = "status" %}
|
||||
{% extends "layout/basic.html" %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="medium-12 columns">
|
||||
<div class="section">
|
||||
<div class="section__body no-padding">
|
||||
<div data-fragment-id="status">
|
||||
<table class="data-table">
|
||||
<colgroup>
|
||||
<col class="col--id">
|
||||
<col class="col--status">
|
||||
<col class="col--os">
|
||||
<col class="col--cpu">
|
||||
<col class="col--memory">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col--id">{{ _('ID') }}</th>
|
||||
<th class="col--status">{{ _('Current Status') }}</th>
|
||||
<th class="col--os">{{ _('OS Info') }}</th>
|
||||
<th class="col--cpu">{{ _('CPU Info') }}</th>
|
||||
<th class="col--memory">{{ _('Memory Info') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for doc in stats %}
|
||||
<tr>
|
||||
<td class="col--id">{{ doc._id|truncate(6, True, '') }}</td>
|
||||
<td class="col--status">{{ doc.status }}</td>
|
||||
<td class="col--os">{{ doc.osinfo }}</td>
|
||||
<td class="col--cpu" data-tooltip="{{ doc.flags }}">{{ doc.cpu }}</td>
|
||||
<td class="col--memory">{{ doc.memory }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,9 @@
|
||||
.page--status
|
||||
.col--id
|
||||
width: 110px
|
||||
|
||||
.col--status
|
||||
width: 100px
|
||||
|
||||
.col--memory
|
||||
width: 150px
|
||||
@@ -3786,6 +3786,11 @@ supports-color@^7.1.0:
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
systeminformation@^4.26.5:
|
||||
version "4.26.5"
|
||||
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-4.26.5.tgz#d2dc77d4cc54b38345d552fcfd00344f49a964a4"
|
||||
integrity sha512-hTVhCYNIsoDtL8brW6wg/UTHmyRfMRItd/+6f6JZtXjmx06FHKBGCyBe7WN6J+FiDIiDfTK7mvMq7hljM6r5OA==
|
||||
|
||||
table@^5.2.3:
|
||||
version "5.4.6"
|
||||
resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
|
||||
|
||||
Reference in new issue
Block a user