aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Ridgers <[email protected]>2024-10-14 10:06:38 +0200
committerGitHub Enterprise <[email protected]>2024-10-14 10:06:38 +0200
commit0fc91c7eeac9df19fa8d29dd99f12493372b501d (patch)
tree8969d3fef106f90cba01c3ef51e56637f2f84c6b /src
parentAdd ability to read the oplog's ReferencedSet, as written by the cook… (#190) (diff)
downloadzen-0fc91c7eeac9df19fa8d29dd99f12493372b501d.tar.xz
zen-0fc91c7eeac9df19fa8d29dd99f12493372b501d.zip
Dashboard: oplog entry data download, more detail, styling tweaks. (#194)
* MSVC's std::fs::path doesn't like appending '/' separated path components * Redirect '/dashboard' to '/dashboard/' * Missed a few copyright headers * Moved unescaped logo somewhere more suitable * More robust catching and displaying of errors * No need for the guard now or for waiting * Formal access to a component's style * Style tables explicitly without instead of via a CSS variable * Highlight a row under the cursor to guide user's eye * Not using css_var() so it was removed * Add more detail to a project's list of oplogs * Disabled test page's CbObject testing * Consider all fields ending in "importedpackageids" as dependencies * Don't wrap sector headers * Package ids were derived with endianess back to front * Moved oplog marker column further left * Adopt a vararg-style to Table.add_row() for cell contents * List and hotlink oplog entries' package data * Modest control over how a table's columns are arranged * Added tables to test column spacing * Keep stat filter input box correctly up to date * A clang-format run * Updated html.zip * validate found oplog directories when doing discover pass --------- Co-authored-by: Dan Engelbrecht <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/zenserver/frontend/frontend.cpp3
-rw-r--r--src/zenserver/frontend/html.zipbin116429 -> 119799 bytes
-rw-r--r--src/zenserver/frontend/html/compactbinary.js2
-rw-r--r--src/zenserver/frontend/html/index.html6
-rw-r--r--src/zenserver/frontend/html/zen.css31
-rw-r--r--src/zenserver/frontend/html/zen.js278
-rw-r--r--src/zenserver/projectstore/projectstore.cpp5
7 files changed, 221 insertions, 104 deletions
diff --git a/src/zenserver/frontend/frontend.cpp b/src/zenserver/frontend/frontend.cpp
index 7ce19363a..31d9e1c94 100644
--- a/src/zenserver/frontend/frontend.cpp
+++ b/src/zenserver/frontend/frontend.cpp
@@ -133,7 +133,8 @@ HttpFrontendService::HandleRequest(zen::HttpServerRequest& Request)
// The given content directory overrides any zip-fs discovered in the binary
if (!m_Directory.empty())
{
- FileContents File = ReadFile(m_Directory / Uri);
+ auto FullPath = m_Directory / std::filesystem::path(Uri).make_preferred();
+ FileContents File = ReadFile(FullPath);
if (!File.ErrorCode)
{
diff --git a/src/zenserver/frontend/html.zip b/src/zenserver/frontend/html.zip
index 0edf64c95..cda479fc8 100644
--- a/src/zenserver/frontend/html.zip
+++ b/src/zenserver/frontend/html.zip
Binary files differ
diff --git a/src/zenserver/frontend/html/compactbinary.js b/src/zenserver/frontend/html/compactbinary.js
index c648e6052..1247e556d 100644
--- a/src/zenserver/frontend/html/compactbinary.js
+++ b/src/zenserver/frontend/html/compactbinary.js
@@ -1,3 +1,5 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
"use strict";
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/zenserver/frontend/html/index.html b/src/zenserver/frontend/html/index.html
index 300b8c62e..fad4bf902 100644
--- a/src/zenserver/frontend/html/index.html
+++ b/src/zenserver/frontend/html/index.html
@@ -2,6 +2,12 @@
<!DOCTYPE html>
<html>
<head>
+ <script>
+ if (window.location.pathname == "/dashboard")
+ {
+ window.location.pathname = "/dashboard/";
+ }
+ </script>
<link rel="shortcut icon" href="favicon.ico">
<link rel="stylesheet" type="text/css" href="zen.css" />
<script src="compactbinary.js"></script>
diff --git a/src/zenserver/frontend/html/zen.css b/src/zenserver/frontend/html/zen.css
index 885c58fc4..a725ffb79 100644
--- a/src/zenserver/frontend/html/zen.css
+++ b/src/zenserver/frontend/html/zen.css
@@ -1,3 +1,5 @@
+/* Copyright Epic Games, Inc. All Rights Reserved. */
+
/* page --------------------------------------------------------------------- */
:root {
@@ -59,6 +61,10 @@ pre {
/* sector ------------------------------------------------------------------- */
+h1, h2, h3 {
+ white-space: nowrap;
+}
+
h1 {
font-size: 1.5em;
width: 100%;
@@ -91,7 +97,6 @@ h3 {
.zen_table {
display: grid;
- grid-template-columns: max-content repeat(calc(var(--zen_columns) - 1), 1fr);
border: 1px solid var(--theme_g2);
border-left-style: none;
margin-bottom: 1.2em;
@@ -110,6 +115,10 @@ h3 {
background-color: var(--theme_p3);
}
+.zen_table > div:hover {
+ background-color: var(--theme_p4);
+}
+
.zen_table > hidden {
visibility: hidden;
display: none;
@@ -295,11 +304,25 @@ h3 {
padding: 1.0em 2em 2em 2em;
width: 100%;
border-top: 1px solid var(--theme_g0);
+ display: flex;
+}
+
+#error > div:nth-child(1) {
+ font-size: 2.5em;
+ font-weight: bolder;
+ font-family: serif;
+ transform: rotate(-13deg);
+ color: var(--theme_p0);
}
-#error > pre:nth-child(2) {
- font-size: 0.8em;
- color: var(--theme_g1);
+#error > div:nth-child(2) {
+ margin-left: 2em;
+}
+
+#error > div:nth-child(2) > pre:nth-child(2) {
+ margin-top: 0.5em;
+ font-size: 0.8em;
+ color: var(--theme_g1);
}
/* stats -------------------------------------------------------------------- */
diff --git a/src/zenserver/frontend/html/zen.js b/src/zenserver/frontend/html/zen.js
index df71cac7b..4d3895d1f 100644
--- a/src/zenserver/frontend/html/zen.js
+++ b/src/zenserver/frontend/html/zen.js
@@ -1,3 +1,5 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
"use strict";
////////////////////////////////////////////////////////////////////////////////
@@ -85,9 +87,9 @@ class ComponentDom extends ComponentBase
return this;
}
- css_var(key, value)
+ style(key, value)
{
- this._element.style.setProperty("--" + key, value);
+ this._element.style[key] = value;
return this;
}
@@ -192,21 +194,38 @@ class TableRow extends Component
////////////////////////////////////////////////////////////////////////////////
class Table extends Component
{
- constructor(parent, column_names, index_base=0)
+ static Flag_EvenSpacing = 1 << 0;
+ static Flag_PackRight = 1 << 1;
+ static Flag_BiasLeft = 1 << 2;
+ static Flag_FitLeft = 1 << 3;
+
+ constructor(parent, column_names, flags=Table.Flag_EvenSpacing, index_base=0)
{
var root = parent.tag().classify("zen_table");
super(root);
- this._index = index_base;
+ var column_style;
+ if (flags & Table.Flag_FitLeft) column_style = "max-content";
+ else if (flags & Table.Flag_BiasLeft) column_style = "2fr";
+ else column_style = "1fr";
+ for (var i = 1; i < column_names.length; ++i)
+ {
+ const style = (flags & Table.Flag_PackRight) ? " auto" : " 1fr";
+ column_style += style;
+ }
+
if (index_base >= 0)
+ {
column_names = ["#", ...column_names];
+ column_style = "max-content " + column_style;
+ }
- this._num_columns = column_names.length;
- root.css_var("zen_columns", this._num_columns);
+ root.style("gridTemplateColumns", column_style);
- this._num_columns = column_names.length;
this._add_row(column_names, false);
+ this._index = index_base;
+ this._num_columns = column_names.length;
this._rows = [];
}
@@ -251,7 +270,7 @@ class Table extends Component
add_row(...args)
{
- var row = this._add_row(...args);
+ var row = this._add_row(args);
this._rows.push(row);
return row;
}
@@ -272,13 +291,13 @@ class PropTable extends Table
{
constructor(parent)
{
- super(parent, ["prop", "value"], -1);
+ super(parent, ["prop", "value"], Table.Flag_FitLeft, -1);
this.classify("zen_proptable");
}
add_property(key, value)
{
- return this.add_row([key, value]);
+ return this.add_row(key, value);
}
add_object(object, friendly=false, prec=2)
@@ -580,6 +599,14 @@ class ZenPage extends Page
zen_store.tag().id("go_home").on_click(() => window.location.search = "");
root.tag("img").attr("src", "favicon.ico").id("ue_logo");
+
+ /*
+ _________ _______ __
+ \____ /___ ___ / ___// |__ ___ ______ ____
+ / __/ __ \ / \ \___ \\_ __// \\_ \/ __ \
+ / \ __// | \/ \| | ( - )| |\/\ __/
+ /______/\___/\__|__/\______/|__| \___/ |__| \___|
+ */
}
set_title(...args)
@@ -654,16 +681,63 @@ class Entry extends ZenPage
for (const dep_name in tree)
{
const dep_section = sub_section.add_section(dep_name);
- const table = new Table(dep_section, ["id", "name"]);
+ const table = new Table(dep_section, ["id", "name"], Table.Flag_FitLeft);
for (const dep_id of tree[dep_name])
{
const cell_values = [dep_id.toString(16)];
- const row = table.add_row(cell_values);
+ const row = table.add_row(...cell_values);
row.get_cell(0).on_click(() => void(0));
}
}
}
+ // data
+ {
+ const sub_section = section.add_section("data");
+ const table = new Table(sub_section, ["name", "actions"], Table.Flag_PackRight);
+ for (const field_name of ["packagedata", "bulkdata"])
+ {
+ var pkg_data = entry.find(field_name);
+ if (pkg_data == undefined)
+ continue;
+
+ for (const item of pkg_data.as_array())
+ {
+ var io_hash;
+ var file_name;
+ for (const field of item.as_object())
+ {
+ if (field.get_name() == "data") io_hash = field.as_value();
+ else if (field.get_name() == "filename") file_name = field.as_value();
+ }
+
+ if (io_hash instanceof Uint8Array)
+ {
+ var ret = "";
+ for (var x of io_hash)
+ ret += x.toString(16).padStart(2, "0");
+ io_hash = ret;
+ }
+
+ const row = table.add_row(file_name);
+
+ const project = this.get_param("project");
+ const oplog = this.get_param("oplog");
+ const link = row.get_cell(0).link(
+ "/" + ["prj", project, "oplog", oplog, io_hash].join("/")
+ );
+
+ const do_nothing = () => void(0);
+ const action_tb = new Toolbar(row.get_cell(-1), true);
+ action_tb.left().add("copy-hash").on_click(async (v) => {
+ await navigator.clipboard.writeText(v);
+ }, io_hash);
+ action_tb.left().add("view");
+ action_tb.left().add("drop");
+ }
+ }
+ }
+
// props
{
const object = entry.to_js_object();
@@ -683,23 +757,32 @@ class Entry extends ZenPage
if (pkg_id == undefined)
continue;
- for (var x of pkg_id.as_value().subarray(0, 8))
+ pkg_id = pkg_id.as_value().subarray(0, 8);
+ for (var i = 7; i >= 0; --i)
{
id <<= 8n;
- id |= BigInt(x);
+ id |= BigInt(pkg_id[i]);
}
break;
}
tree["$id"] = id;
const pkgst_entry = entry.find("packagestoreentry").as_object();
- const imported = pkgst_entry.find("importedpackageids");
- if (imported == undefined)
- return tree;
- var out = tree["imported"] = [];
- for (var item of imported.as_array())
- out.push(item.as_value(BigInt));
+ for (const field of pkgst_entry)
+ {
+ const field_name = field.get_name()
+ if (!field_name.endsWith("importedpackageids"))
+ continue;
+
+ var dep_name = field_name.slice(0, -18);
+ if (dep_name.length == 0)
+ dep_name = "imported";
+
+ var out = tree[dep_name] = [];
+ for (var item of field.as_array())
+ out.push(item.as_value(BigInt));
+ }
return tree;
}
@@ -772,9 +855,7 @@ class Oplog extends ZenPage
for (const entry of entries)
{
- var row = this._entry_table.add_row([
- entry["key"]
- ]);
+ var row = this._entry_table.add_row(entry["key"]);
row.get_cell(0).link("", {
"page" : "entry",
@@ -826,16 +907,20 @@ class Project extends ZenPage
// oplog
section = this.add_section("oplogs");
- var oplog_table = new Table(section, ["name", "actions"])
+ var oplog_table = new Table(
+ section,
+ ["name", "marker", "size", "ops", "expired", "actions"],
+ Table.Flag_PackRight
+ )
var count = 0;
for (const oplog of info["oplogs"])
{
const name = oplog["id"];
- var row = oplog_table.add_row([
- name,
- ]);
+ var info = new Fetcher().resource("prj", project, "oplog", name).json();
+
+ var row = oplog_table.add_row(name);
var cell = row.get_cell(0);
cell.link("", {
@@ -847,6 +932,12 @@ class Project extends ZenPage
cell = row.get_cell(-1);
var action_tb = new Toolbar(cell, true);
action_tb.left().add("drop").on_click((x) => this.drop_oplog(x), name);
+
+ info = await info;
+ row.get_cell(1).text(Friendly.sep(info["markerpath"]));
+ row.get_cell(2).text(Friendly.kib(info["totalsize"]));
+ row.get_cell(3).text(Friendly.sep(info["opcount"]));
+ row.get_cell(4).text(Friendly.sep(info["expired"]));
}
}
@@ -906,22 +997,43 @@ class Test extends ZenPage
const cols = [gen_word(), gen_word(), gen_word(), gen_word()];
var tables = [
new Table(section0, cols),
- new Table(section1, cols, 5),
- new Table(section2, cols, -1),
+ new Table(section1, cols, Table.Flag_EvenSpacing, 5),
+ new Table(section2, cols, Table.Flag_EvenSpacing, -1),
];
for (const table of tables)
{
- table.add_row([gen_word()]);
- table.add_row([gen_word(), gen_word(), gen_word(), gen_word()]);
- table.add_row([gen_word(), gen_word(), gen_para(15, 25), gen_word(), gen_word(), gen_word(), gen_word(), gen_word()]);
+ table.add_row(gen_word());
+ table.add_row(gen_word(), gen_word(), gen_word(), gen_word());
+ table.add_row(gen_word(), gen_word(), gen_para(15, 25), gen_word(), gen_word(), gen_word(), gen_word(), gen_word());
+ }
+
+ // spacing tests
+ {
+ const spacing_section = section0.add_section("spacing");
+ const flags = {
+ "EvenSpacing" : Table.Flag_EvenSpacing,
+ "EvenSpacing|BiasLeft" : Table.Flag_EvenSpacing | Table.Flag_BiasLeft,
+ "PackRight" : Table.Flag_PackRight,
+ };
+ for (const flag_name in flags)
+ {
+ const flag = flags[flag_name];
+ const another_table = new Table(
+ spacing_section,
+ [flag_name, gen_word(), gen_word(), gen_word(), gen_word()],
+ flag,
+ );
+ for (var i = 0; i < 3; ++i)
+ another_table.add_row(gen_para(1, 5), gen_para(1, 3), gen_word(), gen_word(), gen_word());
+ }
}
// prop-table
var pt_section = section0.add_section("prop-table")
var prop_table = new PropTable(pt_section);
for (var i = 0; i < 7; ++i)
- prop_table.add_property(gen_word(), gen_para(1, 14, "/"));
+ prop_table.add_property(gen_word(), gen_para(1, 20, "/"));
// misc
const misc_section = section0.add_section("misc").add_section("misc");
@@ -956,38 +1068,9 @@ class Test extends ZenPage
toolbar.right().add("tbitem2").on_click(tb_item_clicked, 33, -55);
toolbar.right().add("tbitem3").on_click(tb_item_clicked, 44, -88);
- this._cbo_test();
-
// error
throw Error("deliberate error");
}
-
- async _cbo_test()
- {
- var data = new Uint8Array(await (await fetch("/prj/list")).arrayBuffer());
- for (var item of new CbObject(data).as_array())
- {
- for (var subitem of item.as_object())
- {
- console.log(subitem.get_name(), subitem.as_value());
- }
- }
-
- data = new Uint8Array(await (await fetch("/stats")).arrayBuffer());
- {
- var item = new CbObject(data).as_object().find("providers").as_array();
- console.log(item.num());
- for (var subitem of item)
- {
- console.log(subitem.as_value());
- data = new Uint8Array(await (await fetch("/stats/" + subitem.as_value())).arrayBuffer());
- for (var ssitem of new CbObject(data).as_object())
- {
- console.log(ssitem.get_name(), ssitem.as_value());
- }
- }
- }
- }
}
@@ -1010,11 +1093,11 @@ class Start extends ZenPage
for (const project of await new Fetcher().resource("/prj/list").json())
{
- var row = table.add_row([
+ var row = table.add_row(
"",
project.ProjectRootDir,
project.EngineRootDir,
- ]);
+ );
var cell = row.get_cell(0);
cell.tag().text(project.Id).on_click((x) => this.view_project(x), project.Id);
@@ -1034,7 +1117,7 @@ class Start extends ZenPage
"size mem",
"cid total",
];
- const stats_table = new Table(section, columns);
+ const stats_table = new Table(section, columns, Table.Flag_PackRight);
var providers = new Fetcher().resource("stats").json();
for (var provider of (await providers)["providers"])
{
@@ -1048,7 +1131,7 @@ class Start extends ZenPage
values.push(stats.cid.size.total);
}
catch {}
- row = stats_table.add_row(values);
+ row = stats_table.add_row(...values);
row.get_cell(0).tag().text(provider).on_click((x) => this.view_stat(x), provider);
}
}
@@ -1153,10 +1236,8 @@ class Stat extends ZenPage
tb_right.add("-none-").on_click((x) => this.update_filter(""));
for (var preset of ["read.", "write.", ".request", ".bytes"])
tb_right.add(preset).on_click((x) => this.update_filter(x), preset);
- {
- var input = tb_right.add("", "input")
- input.on("change", (x) => this.update_filter(x.inner().value), input);
- }
+ this._filter_input = tb_right.add("", "input")
+ this._filter_input.on("change", (x) => this.update_filter(x.inner().value), this._filter_input);
this._table = new PropTable(section);
@@ -1170,10 +1251,11 @@ class Stat extends ZenPage
toolbar.left().add(name).on_click((x) => this.view_category(x), name);
}
+ var filter = this.get_param("filter");
+
first = this.get_param("view", first);
this.view_category(first);
- var filter = this.get_param("filter");
if (filter)
this.update_filter(filter);
}
@@ -1184,11 +1266,13 @@ class Stat extends ZenPage
this._table.clear();
this._table.add_object(this._stats[name], friendly, 3);
this.set_param("view", name);
- this.set_param("filter", "");
+ this.update_filter("");
}
update_filter(needle)
{
+ this._filter_input.attr("value", needle);
+
this.set_param("filter", needle);
if (!needle)
return this._table.filter();
@@ -1226,7 +1310,29 @@ class Stat extends ZenPage
////////////////////////////////////////////////////////////////////////////////
-async function main_guarded()
+function display_error(message, stack)
+{
+ const pane = new Component(document.body).tag().id("error");
+ pane.tag().text("!");
+ const content = pane.tag();
+ content.tag("pre").text(message);
+ content.tag("pre").text(stack);
+}
+
+window.addEventListener("error", function(evt) {
+ const reason = evt.error;
+ display_error(reason.message, reason.stack);
+});
+
+window.addEventListener("unhandledrejection", function(evt) {
+ const reason = evt.reason;
+ display_error(reason.message, reason.stack);
+});
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+async function main()
{
const params = new URLSearchParams(window.location.search);
const page = params.get("page");
@@ -1248,29 +1354,5 @@ async function main_guarded()
return;
}
- return impl.main();
+ impl.main();
}
-
-////////////////////////////////////////////////////////////////////////////////
-async function main()
-{
- try
- {
- return await main_guarded();
- }
- catch (e)
- {
- var pane = new Component(document.body).tag().id("error");
- pane.tag("pre").text(e);
- pane.tag("pre").text(e.stack);
- throw e;
- }
-}
-
-/*
-_________ _______ __
-\____ /___ ___ / ___// |__ ___ ______ ____
- / __/ __ \ / \ \___ \\_ __// \\_ \/ __ \
- / \ __// | \/ \| | ( - )| |\/\ __/
-/______/\___/\__|__/\______/|__| \___/ |__| \___|
-*/
diff --git a/src/zenserver/projectstore/projectstore.cpp b/src/zenserver/projectstore/projectstore.cpp
index a5bd1859b..0e6b2d3c9 100644
--- a/src/zenserver/projectstore/projectstore.cpp
+++ b/src/zenserver/projectstore/projectstore.cpp
@@ -3065,7 +3065,10 @@ ProjectStore::Project::ScanForOplogs() const
Oplogs.reserve(DirContent.Directories.size());
for (const std::filesystem::path& DirPath : DirContent.Directories)
{
- Oplogs.push_back(DirPath.filename().string());
+ if (Oplog::ExistsAt(DirPath))
+ {
+ Oplogs.push_back(DirPath.filename().string());
+ }
}
}