Release 1.0.0 with server info console

This commit is contained in:
Artem Kokos
2026-05-21 20:46:04 +07:00
parent 85c840ba1b
commit 61b21c63ea
12 changed files with 766 additions and 5 deletions

View File

@@ -39,6 +39,7 @@ createApp({
isAdmin: false,
isMaster: false,
authName: "",
serverInfo: null,
groups: {},
devices: [],
sliders: {},
@@ -86,6 +87,7 @@ createApp({
this.isAdmin = false;
this.isMaster = false;
this.authName = "";
this.serverInfo = null;
this.groups = {};
this.devices = [];
this.sliders = {};
@@ -115,6 +117,104 @@ createApp({
const group = this.groups[targetId];
return group ? group.name : null;
},
serverDisplayName() {
if (this.serverInfo?.instance_name) {
return this.serverInfo.instance_name;
}
return this.serverInfo?.app_name || "Ignis Core";
},
serverDisplaySubtitle() {
if (this.serverInfo?.instance_name) {
return this.serverInfo.app_name || "Ignis Core";
}
if (this.serverInfo?.diagnostics_visible) {
return "Подключение активно и готово к управлению.";
}
return "Подключение активно. Операционная диагностика скрыта для гостевого доступа.";
},
shortSha(value) {
if (!value) {
return null;
}
return value.length <= 7 ? value : value.slice(0, 7);
},
formatServerTimestamp(iso) {
if (!iso) {
return "unknown";
}
const parsed = new Date(iso);
if (Number.isNaN(parsed.getTime())) {
return iso;
}
const pad = (value) => String(value).padStart(2, "0");
return `${parsed.getUTCFullYear()}-${pad(parsed.getUTCMonth() + 1)}-${pad(parsed.getUTCDate())} ${pad(parsed.getUTCHours())}:${pad(parsed.getUTCMinutes())} UTC`;
},
formatServerBuild(build) {
if (!build) {
return "build info unavailable";
}
const parts = [`v${build.version}`];
const shortSha = this.shortSha(build.git_sha);
if (shortSha) {
parts.push(shortSha);
}
if (build.build_date) {
parts.push(this.formatServerTimestamp(build.build_date));
}
return parts.join(" · ");
},
formatDuration(totalSeconds, maxParts = 2) {
const seconds = Math.max(Number(totalSeconds || 0), 0);
if (seconds < 60) {
return "меньше минуты";
}
const units = [
{ size: 86400, forms: ["день", "дня", "дней"] },
{ size: 3600, forms: ["час", "часа", "часов"] },
{ size: 60, forms: ["минута", "минуты", "минут"] },
];
let remaining = seconds;
const parts = [];
units.forEach((unit) => {
if (parts.length >= maxParts) {
return;
}
const value = Math.floor(remaining / unit.size);
if (value <= 0) {
return;
}
parts.push(`${value} ${this.pluralRu(value, ...unit.forms)}`);
remaining -= value * unit.size;
});
return parts.join(" ");
},
formatUptime(totalSeconds) {
return this.formatDuration(totalSeconds, 2);
},
formatRelativeUptime(totalSeconds) {
const seconds = Math.max(Number(totalSeconds || 0), 0);
if (seconds < 60) {
return "только что";
}
return `${this.formatDuration(seconds, 2)} назад`;
},
pluralRu(count, one, few, many) {
const mod10 = count % 10;
const mod100 = count % 100;
if (mod10 === 1 && mod100 !== 11) {
return one;
}
if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) {
return few;
}
return many;
},
async request(path, { method = "GET", query = null, body = null } = {}) {
let url = path;
if (query) {
@@ -185,12 +285,17 @@ createApp({
this.isFetching = true;
try {
const [groupsData, devicesData, scenesData] = await Promise.all([
const [serverInfoData, groupsData, devicesData, scenesData] = await Promise.all([
this.request("/system/info"),
this.request("/devices/groups"),
this.request("/devices"),
this.request("/devices/scenes"),
]);
if (serverInfoData) {
this.serverInfo = serverInfoData;
}
if (groupsData) {
this.groups = groupsData;
Object.keys(this.groups).forEach((id) => {